pax_global_header00006660000000000000000000000064147514034410014515gustar00rootroot0000000000000052 comment=fa8cf9c81b5d3e95329b71c1f7c1ea03b43fde00 libzpc-1.3.0/000077500000000000000000000000001475140344100130015ustar00rootroot00000000000000libzpc-1.3.0/.gitignore000066400000000000000000000000361475140344100147700ustar00rootroot00000000000000doc/html/ doc/latex/ .vscode/ libzpc-1.3.0/.indent.pro000066400000000000000000000063411475140344100150660ustar00rootroot00000000000000// *** libzpc indent options *** // // To use the indent tool with the specified options, copy this file to your // home directory or set the INDENT_PROFILE environment variable's value to // name this file e.g., do // // export INDENT_PROFILE=`pwd`/.indent.pro // // from the root of the source tree. // // See indent(1). // *** INVOKIND INDENT *** //--standard-output //--ignore-profile // *** COMMON STYLES *** // We use none of them. //--gnu-style //--k-and-r-style //--original //--linux // *** BLANK LINES *** //--blank-lines-after-declarations --no-blank-lines-after-declarations --blank-lines-after-procedures //--no-blank-lines-after-procedures // Puts blank line before header. //--blank-lines-before-block-comments --no-blank-lines-before-block-comments --swallow-optional-blank-lines //--leave-optional-blank-lines // *** COMMENTS *** // Set in BLANK LINES section. //--blank-lines-before-block-comments //--no-blank-lines-before-block-comments --format-all-comments //--dont-format-comments // Puts a trailing space after /* //--format-first-column-comments --dont-format-first-column-comments --comment-line-length80 //--fix-nested-comments --line-comments-indentation0 --comment-indentation0 --declaration-comment-column0 --else-endif-column0 --left-justify-declarations //--dont-left-justify-declarations //--dont-tab-align-comments //--comment-delimiters-on-blank-lines --no-comment-delimiters-on-blank-lines --start-left-side-of-comments //--dont-star-comments // *** STATEMENTS *** --braces-on-if-line //--braces-after-if-line //--brace-indent0 --cuddle-else //--dont-cuddle-else --cuddle-do-while //--dont-cuddle-do-while //--single-line-conditionals --case-indentation0 --case-brace-indentation0 //--space-special-semicolon --dont-space-special-semicolon //--space-after-procedure-calls --no-space-after-function-call-names //--space-after-cast --no-space-after-casts //--blank-before-sizeof --space-after-for //--no-space-after-for --space-after-if //--no-space-after-if --space-after-while //--no-space-after-while //--space-after-parentheses --no-space-after-parentheses --struct-brace-indentation0 // *** DECLARATIONS *** --declaration-indentation0 //--blank-lines-after-commas --no-blank-lines-after-commas //--break-function-decl-args --dont-break-function-decl-args //--break-function-decl-args-end --dont-break-function-decl-args-end --procnames-start-lines //--dont-break-procedure-type --braces-on-struct-decl-line //--braces-after-struct-decl-line //--braces-on-func-def-line --braces-after-func-def-line //--spaces-around-initializers // *** IDENTATION *** --use-tabs //--no-tabs --indent-level8 --continuation-indentation4 //--continue-at-parentheses --dont-line-up-parentheses --paren-indentation0 --tab-size8 --align-with-spaces --parameter-indentation4 //--no-parameter-indentation // Overridden by --preprocessor-indentationn. //--leave-preprocessor-space //-nps --preprocessor-indentation1 --indent-label0 // *** BREAKING LONG LINES *** --line-length80 --break-before-boolean-operator //--break-after-boolean-operator //--honour-newlines --ignore-newlines //--gettext-strings --no-gettext-strings // *** MISCELLANEOUS OPTIONS *** //--verbose --no-verbosity //--preserve-mtime libzpc-1.3.0/.travis.yml000066400000000000000000000007521475140344100151160ustar00rootroot00000000000000arch: s390x os: linux dist: jammy language: cpp sudo: required env: | CFLAGS="-O3 -Wextra -Wextra -Werror" CXXFLAGS="-O3 -Wextra -Wextra -Werror" compiler: - gcc - clang before_install: - sudo apt-get update -qq - sudo apt-get install cmake libjson-c-dev script: - set -o pipefail - mkdir build 2> >(tee) && cd build 2> >(tee) - cmake -DBUILD_TEST=ON .. 2> >(tee) - make 2> >(tee) libzpc-1.3.0/CHANGES.md000066400000000000000000000020041475140344100143670ustar00rootroot00000000000000Changelog {#changes} === **Version 1.3.0** - Support for Ultravisor retrievable secrets - Handle CCA cipher key token with Encrypted V0 payload - bug fixes **Version 1.2.0** - Support for get/set intermediate iv for CBC and XTS - Support for internal iv for GCM - Fix AES EP11 version 6 key support for generate and import_clear - Exploit KBLOB2PROTK3 ioctl for clear AES and EC keys **Version 1.1.1** - Exploit PKEY_KBLOB2PROTK2 for AES EP11 version 6 keys **Version 1.1.0** - Implements an ECC-KEY API : `zpc/ecc_key.h`. - Implements an ECDSA-CTX API : `zpc/ecdsa_ctx.h`. **Version 1.0.1** - Updated spec file for rpm build **Version 1.0** - Implements an error API : `zpc/error.h`. - Implements an AES-KEY API : `zpc/aes_key.h`. - Implements an AES-GCM API : `zpc/aes_gcm.h`. - Implements an AES-CCM API : `zpc/aes_ccm.h`. - Implements an AES-XTS API : `zpc/aes_xts.h`. - Implements an AES-CBC API : `zpc/aes_cbc.h`. - Implements an AES-ECB API : `zpc/aes_ecb.h`. - Implements an AES-CMAC API : `zpc/aes_cmac.h`. libzpc-1.3.0/CMakeLists.txt000066400000000000000000000266721475140344100155560ustar00rootroot00000000000000########################################################### set(ZPC_NAME "libzpc" ) set(ZPC_DESCRIPTION "IBM Z Protected-key Crypto library") set(ZPC_VERSION_MAJOR 1 ) set(ZPC_VERSION_MINOR 3 ) set(ZPC_VERSION_PATCH 0 ) ########################################################### cmake_minimum_required( VERSION 3.10 ) # Honor symbol visibility properties for all target types. # https://cmake.org/cmake/help/git-stage/policy/CMP0063.html if(POLICY CMP0063) cmake_policy(SET CMP0063 NEW) endif() # New in version 3.24: prefer to set the timestamps of all extracted contents # to the time of the extraction. # https://cmake.org/cmake/help/git-stage/policy/CMP0135.html if(POLICY CMP0135) cmake_policy(SET CMP0135 NEW) endif() set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_FLAGS_DEBUG "-Wall -Wextra -m64 -g -O0") set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_FLAGS_DEBUG "-Wall -Wextra -m64 -g -O0") project(${ZPC_NAME} VERSION ${ZPC_VERSION_MAJOR}.${ZPC_VERSION_MINOR}.${ZPC_VERSION_PATCH} DESCRIPTION ${ZPC_DESCRIPTION} LANGUAGES CXX C ASM ) set(ZPC_HEADERS include/zpc/error.h include/zpc/aes_key.h include/zpc/aes_gcm.h include/zpc/aes_ccm.h include/zpc/aes_xts.h include/zpc/aes_cbc.h include/zpc/aes_ecb.h include/zpc/aes_cmac.h include/zpc/ecc_key.h include/zpc/ecdsa_ctx.h ) set(ZPC_SOURCES src/globals.c src/error.c src/misc.c src/misc_asm.S src/aes_key.c src/aes_ecb.c src/aes_cbc.c src/aes_xts.c src/aes_cmac.c src/aes_ccm.c src/aes_gcm.c src/ecc_key.c src/ecdsa_ctx.c src/pvsecrets.c src/zkey/utils.c src/zkey/pkey.c src/zkey/cca.c src/zkey/ep11.c src/zkey/lib/util_base.c src/zkey/lib/util_file.c src/zkey/lib/util_libc.c src/zkey/lib/util_panic.c src/zkey/lib/util_path.c src/zkey/lib/util_prg.c ) find_library(PTHREAD REQUIRED NAMES pthread ) find_library(JSON_C REQUIRED NAMES json-c ) add_definitions( -D_GNU_SOURCE ) set(ZPC_LIBS ${PTHREAD} ${CMAKE_DL_LIBS} ) add_library(zpc ${ZPC_SOURCES}) set_target_properties(zpc PROPERTIES VERSION ${ZPC_VERSION_MAJOR}.${ZPC_VERSION_MINOR}.${ZPC_VERSION_PATCH} SOVERSION ${ZPC_VERSION_MAJOR} PUBLIC_HEADER "${ZPC_HEADERS}" C_VISIBILITY_PRESET hidden CXX_VISIBILITY_PRESET hidden LINK_FLAGS "-Wl,--version-script=${CMAKE_SOURCE_DIR}/libzpc.map" ) target_include_directories(zpc PRIVATE include src src/zkey) target_link_libraries(zpc ${ZPC_LIBS}) target_compile_definitions( zpc PRIVATE ZPC_VERSION_MAJOR=${ZPC_VERSION_MAJOR} ZPC_VERSION_MINOR=${ZPC_VERSION_MINOR} ZPC_VERSION_PATCH=${ZPC_VERSION_PATCH} ) configure_file(libzpc.pc.in libzpc.pc @ONLY) include(GNUInstallDirs) install( TARGETS zpc LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/zpc/ ) install( FILES ${CMAKE_BINARY_DIR}/libzpc.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) option(BUILD_TEST OFF) if (BUILD_TEST) enable_testing() set(GTEST_URL https://github.com/google/googletest/archive/refs/tags/release-1.11.0.zip ) set(GTEST_SHA256 353571c2440176ded91c2de6d6cd88ddd41401d14692ec1f99e35d013feda55a ) set(WYCHEPROOF_GIT https://github.com/google/wycheproof.git ) set(WYCHEPROOF_TAG 2196000605e45d91097147c9c71f26b72af58003 ) set(NIST_AES_URL https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/aes/aesmmt.zip ) set(NIST_AES_SHA256 12d1616f7a713e807714055973f04efc402f46a14e3d81869717c7ace4ecbaf0 ) set(NIST_AES_GCM_URL https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/gcmtestvectors.zip ) set(NIST_AES_GCM_SHA256 f9fc479e134cde2980b3bb7cddbcb567b2cd96fd753835243ed067699f26a023 ) set(NIST_AES_CCM_URL https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/ccmtestvectors.zip ) set(NIST_AES_CCM_SHA256 0e3c96761bd8f1a0b4dfe666146c32f7d367a49968375ff091b8da9ecaa673aa ) set(NIST_AES_CCM_URL https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/ccmtestvectors.zip ) set(NIST_AES_CCM_SHA256 0e3c96761bd8f1a0b4dfe666146c32f7d367a49968375ff091b8da9ecaa673aa ) set(NIST_AES_CMAC_URL https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/cmactestvectors.zip ) set(NIST_AES_CMAC_SHA256 bdda4edade394c9a2ae74d9cd0921caa120c911a5e735e37abf39d0d5f062be1 ) set(NIST_AES_XTS_URL https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/aes/XTSTestVectors.zip ) set(NIST_AES_XTS_SHA256 67bb04b018182f65530596786e7783f817d2e56509bf3b1f066609b8e3e29c36 ) set(NIST_ECDSA_URL https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/components/186-3ecdsasiggencomponenttestvectors.zip ) set(NIST_ECDSA_SHA256 cf07d0b3c961032138a072feba237be51da6ff1f9f5af1230e1d6e84858a164f ) include(ExternalProject) ExternalProject_Add(nist_aes URL ${NIST_AES_URL} URL_HASH SHA256=${NIST_AES_SHA256} PREFIX ${CMAKE_BINARY_DIR}/nist_aes CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" ) ExternalProject_Get_Property(nist_aes SOURCE_DIR) set(NIST_AES_SOURCE_DIR ${SOURCE_DIR} ) add_custom_command( OUTPUT nist_aes_ecb.json COMMAND ${CMAKE_SOURCE_DIR}/misc/nist2json_aes_ecb.pl ${NIST_AES_SOURCE_DIR}/ECBMMT* WORKING_DIRECTORY ${CMAKE_BINARY_DIR} DEPENDS nist_aes ) add_custom_target(nist_aes_ecb_json ALL DEPENDS nist_aes_ecb.json) add_custom_command( OUTPUT nist_aes_cbc.json COMMAND ${CMAKE_SOURCE_DIR}/misc/nist2json_aes_cbc.pl ${NIST_AES_SOURCE_DIR}/CBCMMT* WORKING_DIRECTORY ${CMAKE_BINARY_DIR} DEPENDS nist_aes ) add_custom_target(nist_aes_cbc_json ALL DEPENDS nist_aes_cbc.json) ExternalProject_Add(nist_aes_xts URL ${NIST_AES_XTS_URL} URL_HASH SHA256=${NIST_AES_XTS_SHA256} PREFIX ${CMAKE_BINARY_DIR}/nist_aes_xts CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" ) ExternalProject_Get_Property(nist_aes_xts SOURCE_DIR) set(NIST_AES_XTS_SOURCE_DIR ${SOURCE_DIR} ) add_custom_command( OUTPUT nist_aes_xts.json COMMAND ${CMAKE_SOURCE_DIR}/misc/nist2json_aes_xts.pl ${NIST_AES_XTS_SOURCE_DIR}/'format tweak value input - 128 hex str'/* WORKING_DIRECTORY ${CMAKE_BINARY_DIR} DEPENDS nist_aes_xts ) add_custom_target(nist_aes_xts_json ALL DEPENDS nist_aes_xts.json) ExternalProject_Add(nist_aes_gcm URL ${NIST_AES_GCM_URL} URL_HASH SHA256=${NIST_AES_GCM_SHA256} PREFIX ${CMAKE_BINARY_DIR}/nist_aes_gcm CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" ) ExternalProject_Get_Property(nist_aes_gcm SOURCE_DIR) set(NIST_AES_GCM_SOURCE_DIR ${SOURCE_DIR} ) add_custom_command( OUTPUT nist_aes_gcm.json COMMAND ${CMAKE_SOURCE_DIR}/misc/nist2json_aes_gcm.pl ${NIST_AES_GCM_SOURCE_DIR}/* WORKING_DIRECTORY ${CMAKE_BINARY_DIR} DEPENDS nist_aes_gcm ) add_custom_target(nist_aes_gcm_json ALL DEPENDS nist_aes_gcm.json) ExternalProject_Add(nist_aes_ccm URL ${NIST_AES_CCM_URL} URL_HASH SHA256=${NIST_AES_CCM_SHA256} PREFIX ${CMAKE_BINARY_DIR}/nist_aes_ccm CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" ) ExternalProject_Get_Property(nist_aes_ccm SOURCE_DIR) set(NIST_AES_CCM_SOURCE_DIR ${SOURCE_DIR} ) ExternalProject_Add(nist_aes_cmac URL ${NIST_AES_CMAC_URL} URL_HASH SHA256=${NIST_AES_CMAC_SHA256} PREFIX ${CMAKE_BINARY_DIR}/nist_aes_cmac CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" ) ExternalProject_Get_Property(nist_aes_cmac SOURCE_DIR) set(NIST_AES_CMAC_SOURCE_DIR ${SOURCE_DIR} ) ExternalProject_Add(nist_ecdsa URL ${NIST_ECDSA_URL} URL_HASH SHA256=${NIST_ECDSA_SHA256} PREFIX ${CMAKE_BINARY_DIR}/nist_ecdsa CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" ) ExternalProject_Get_Property(nist_ecdsa SOURCE_DIR) set(NIST_ECDSA_SOURCE_DIR ${SOURCE_DIR} ) add_custom_command( OUTPUT nist_ecdsa.json COMMAND chmod 755 ${CMAKE_SOURCE_DIR}/misc/nist2json_ecdsa.pl && ${CMAKE_SOURCE_DIR}/misc/nist2json_ecdsa.pl ${NIST_ECDSA_SOURCE_DIR}/SigGenComponent.txt WORKING_DIRECTORY ${CMAKE_BINARY_DIR} DEPENDS nist_ecdsa ) add_custom_target(nist_ecdsa_json ALL DEPENDS nist_ecdsa.json) add_custom_command( OUTPUT nist_eddsa.json COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/misc/nist_eddsa.json ${CMAKE_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) add_custom_target(nist_eddsa_json ALL DEPENDS nist_eddsa.json) ExternalProject_Add(wycheproof GIT_REPOSITORY ${WYCHEPROOF_GIT} GIT_TAG ${WYCHEPROOF_TAG} PREFIX ${CMAKE_BINARY_DIR}/wycheproof CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" ) ExternalProject_Add(gtest URL ${GTEST_URL} URL_HASH SHA256=${GTEST_SHA256} PREFIX ${CMAKE_BINARY_DIR}/gtest INSTALL_COMMAND "" TEST_COMMAND "" ) ExternalProject_Get_Property(gtest SOURCE_DIR BINARY_DIR) set(GTEST_INCLUDE_DIR ${SOURCE_DIR}/googletest/include ) set(GTEST_LIB_DIR ${BINARY_DIR}/lib ) set(ZPC_TEST_LIBS ${GTEST_LIB_DIR}/libgtest_main.a ${GTEST_LIB_DIR}/libgtest.a ${PTHREAD} ${JSON_C} zpc ) set(ZPC_TEST_SOURCES test/testlib.cc test/b_platform.c test/b_headers.c test/b_error.c test/b_aes_key.c test/b_aes_ecb.c test/b_aes_cbc.c test/b_aes_xts.c test/b_aes_cmac.c test/b_aes_ccm.c test/b_aes_gcm.c test/b_ecc_key.c test/b_ecdsa_ctx.c test/t_system.cc test/t_testlib.cc test/t_environment.cc test/t_error.cc test/t_aes_key.cc test/t_aes_ecb.cc test/t_aes_cbc.cc test/t_aes_cmac.cc test/t_aes_xts.cc test/t_aes_ccm.cc test/t_aes_gcm.cc test/t_ecc_key.cc test/t_ecdsa_ctx.cc ) add_executable(runtest ${ZPC_TEST_SOURCES}) add_dependencies(runtest gtest) target_link_libraries(runtest ${ZPC_TEST_LIBS}) target_include_directories(runtest PRIVATE include src ${GTEST_INCLUDE_DIR}) include(GoogleTest) gtest_discover_tests(runtest) endif () ########################################################### # doc option(BUILD_DOC OFF) if (BUILD_DOC) find_package(Doxygen) if (DOXYGEN_FOUND) set(DOXYFILE ${CMAKE_SOURCE_DIR}/doc/Doxyfile ) add_custom_target(doc ALL COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) endif () endif () libzpc-1.3.0/CONTRIBUTING.md000066400000000000000000000027341475140344100152400ustar00rootroot00000000000000Contributing {#contrib} === You can contribute to `libzpc` by submitting issues (feature requests, bug reports) or pull requests (code contributions) to the GitHub repository. Bug reports --- When filing a bug report, please include all relevant information. In all cases include the `libzpc` version, operating system and kernel version used. Additionally, if it is a build error, include the toolchain version used. If it is a runtime error, include the crypto adapter config and processor model used. Ideally, detailed steps on how to reproduce the issue would be included. Code contributions --- All code contributions are reviewed by the `libzpc` maintainers who reverve the right to accept or reject a pull request. Please state clearly if your pull request changes the `libzpc` API or ABI, and if so, whether the changes are backward compatible. If your pull request resolves an issue, please put a `"Fixes #"` line in the commit message. Ideally, the pull request would add a corresponding regression test. If your pull request adds a new feature, please add a corresponding unit test. The code base is formatted using the `indent` tool with the options specified in the enclosed `.indent.pro` file. All code contributions must not violate this coding style. When formatting `libzpc` code, you can use `indent` with the prescribed options by copying the file to your home directory or by setting the `INDENT_PROFILE` environment variable's value to name the file. libzpc-1.3.0/LICENSE000066400000000000000000000020451475140344100140070ustar00rootroot00000000000000Copyright IBM Corp. 2001, 2017, 2020 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. libzpc-1.3.0/README.md000066400000000000000000000132501475140344100142610ustar00rootroot00000000000000Introduction {#index} === The IBM Z Protected-key Crypto library `libzpc` is an open-source library targeting the 64-bit Linux on IBM Z (s390x) platform. It provides interfaces for cryptographic primitives. The underlying implementations make use of z/Architecture's extensive performance-boosting hardware support and its *protected-key* feature which ensures that key material is never present in main memory at any time. The `libzpc` source is hosted on [GitHub](https://github.com/opencryptoki/libzpc). Supported crypto --- Encryption (Cipher): AES-128-ECB, AES-192-ECB, AES-256-ECB AES-128-CBC, AES-192-CBC, AES-256-CBC AES-128-XTS, AES-256-XTS Message authentication (MAC): AES-128-CMAC, AES-192-CMAC, AES-256-CMAC Authenticated Encryption (AEAD): AES-128-CCM, AES-192-CCM, AES-256-CCM AES-128-GCM, AES-192-GCM, AES-256-GCM Elliptic-curve digital signature create/verify (ECDSA): prime256, oid = 1.2.840.10045.3.1.7 secp384, oid = 1.3.132.0.34 secp521, oid = 1.3.132.0.35 ed25519, oid = 1.3.101.112 ed448, oid = 1.3.101.113 Building --- Basic prerequisites for building the library only: - Linux kernel >= 5.7 - C99 compiler (clang, gcc) - libpthread - cmake >= 3.10 - make Additional prerequisites for building the test program: - C++11 compiler (clang, g++) - libjson-c devel package >= 0.13 - internet connection Additional prerequisites for building the html and latex doc: - doxygen >= 1.8.17 - latex, bibtex Additional hardware and software prerequisites for ECDSA: - Message security assist (MSA) 9 (IBM z15 or later) - Crypto Express 7S CCA coprocessor (CEX7C) or later for CCA type keys - Crypto Express 7S EP11 coprocessor (CEX7P) or later for EP11 type keys - CCA host library version 7.1 or later for CCA type keys - EP11 host library version 3.0 or later for EP11 type keys Building `libzpc`: mkdir build && cd build cmake .. make The following options can be passed to `cmake`: - `-DCMAKE_INSTALL_PREFIX=` : Change the install prefix from `/usr/local/` to ``. - `-DCMAKE_BUILD_TYPE=` : Choose predefined build options. The choices for `` are `Debug`, `Release`, `RelWithDebInfo`, and `MinSizeRel`. - `-DBUILD_SHARED_LIBS=ON` : Build a shared object (instead of an archive). - `-DBUILD_TEST=ON` : Build the test program. - `-DBUILD_DOC=ON` : Build the html and latex doc. See `cmake(1)`. Custom compile options can also be passed to `cmake` via the `CFLAGS` and `CXXFLAGS` environment variables in the usual way. Testing --- To run all tests, do ./runtest from the build directory. For AES, the following environment variables can be passed to `./runtest`: - `ZPC_TEST_AES_KEY_TYPE=` : The choices for `` are `ZPC_AES_KEY_TYPE_CCA_DATA`, `ZPC_AES_KEY_TYPE_CCA_CIPHER` and `ZPC_AES_KEY_TYPE_EP11`. AES tests are skipped if this variable is unset or its value is invalid. - `ZPC_TEST_AES_KEY_SIZE=` : The choices for `` are `128`, `192` and `256`. AES tests are skipped if this variable is unset or its value is invalid. - `ZPC_TEST_AES_KEY_FLAGS=` : `` is a 4 byte unsigned integer value that specifies the key's flags. `` defaults to `0` if this variable is unset or its value is invalid. - `ZPC_TEST_AES_KEY_MKVP=` : Test the APQNs that match `` and key type. - `ZPC_TEST_AES_KEY_APQNS=` : Test the ``. For ECDSA, the following environment variables can be passed to `./runtest`: - `ZPC_TEST_EC_KEY_TYPE=` : The choices for `` are `ZPC_EC_KEY_TYPE_CCA` and `ZPC_EC_KEY_TYPE_EP11`. ECDSA tests are skipped if this variable is unset or its value is invalid. - `ZPC_TEST_EC_KEY_CURVE=` : The choices for `` are `p256` (prime256), `p384` (secp384), `p521` (secp521), `ed25519` (ed25519) and `ed448` (ed448). ECDSA tests are skipped if this variable is unset or its value is invalid. - `ZPC_TEST_EC_KEY_FLAGS=` : `` is a 4 byte unsigned integer value that specifies the key's flags. `` defaults to `0` if this variable is unset or its value is invalid. - `ZPC_TEST_EC_KEY_MKVP=` : Test the APQNs that match `` and key type. - `ZPC_TEST_EC_KEY_APQNS=` : Test the ``. See ./runtest -h for help. Installing --- To install the shared library, do sudo make install sudo ldconfig Configuration --- To do something useful with `libzpc`, at least one CryptoExpress (CEX) HSM with a master key configuration is required. The device drivers for CEX adapters are documented in chapters 54 and 57 of the kernel 5.7 version of [Linux on Z and LinuxONE - Device Drivers, Features, and Commands](https://www.ibm.com/support/knowledgecenter/linuxonibm/liaaf/lnz_r_dd.html). Here are instructions on [how to set an AES master key](https://www.ibm.com/support/knowledgecenter/linuxonibm/liaaf/lnz_r_dtke.html) for a CEX adapter in CCA coprocessor mode using the Trusted Key Entry (TKE). Programming --- Applications include the `` header files corresponding to the APIs required and link with `-lzp`. With the exeption of `zpc_error_string`, all `libzpc` function return either no value or an integer which is either zero (in case of success) of a non-zero error code (in case of failure). In case of multiple errors, the `libzpc` API leaves the precedence of error codes undefined. Therefore, applications should always check for a non-zero return value before handling specific errors e.g.: rc = zpc_foo(); if (rc) { /* Handle specific error codes. */ fprintf(stderr, "Error: %d (%s).\n", rc, zpc_error_string(rc)); } Debugging --- Setting the environment variable `ZPC_DEBUG=1` will have the library print debug information to `stderr`. License --- See `LICENSE` file. libzpc-1.3.0/doc/000077500000000000000000000000001475140344100135465ustar00rootroot00000000000000libzpc-1.3.0/doc/DOC.md000066400000000000000000000002211475140344100144700ustar00rootroot00000000000000doc === UMLet --- The `.uxf` (UMLet diagram format) files can be edited with the UMLet tool and exported to other format like `.eps` or `.jpg`. libzpc-1.3.0/doc/Doxyfile000066400000000000000000000321751475140344100152640ustar00rootroot00000000000000# Doxyfile 1.8.17 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = libzpc PROJECT_NUMBER = 1.0 PROJECT_BRIEF = "IBM Z Protected-key Crypto library" PROJECT_LOGO = OUTPUT_DIRECTORY = doc CREATE_SUBDIRS = NO ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English OUTPUT_TEXT_DIRECTION = None BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = include STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO JAVADOC_BANNER = NO QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 4 ALIASES = TCL_SUBST = OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO OPTIMIZE_OUTPUT_SLICE = NO EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES TOC_INCLUDE_HEADINGS = 5 AUTOLINK_SUPPORT = YES BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO GROUP_NESTED_COMPOUNDS = NO SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO INLINE_SIMPLE_STRUCTS = NO TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_PRIV_VIRTUAL = NO EXTRACT_PACKAGE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = NO EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO HIDE_SCOPE_NAMES = YES HIDE_COMPOUND_REFERENCE= NO SHOW_INCLUDE_FILES = NO SHOW_GROUPED_MEMB_INC = NO FORCE_LOCAL_INCLUDES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = NO SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO GENERATE_TODOLIST = NO GENERATE_TESTLIST = NO GENERATE_BUGLIST = NO GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = CITE_BIB_FILES = doc/references.bib #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = YES WARN_AS_ERROR = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- INPUT = include/zpc \ README.md \ CHANGES.md \ CONTRIBUTING.md INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.idl \ *.ddl \ *.odl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.cs \ *.d \ *.php \ *.php4 \ *.php5 \ *.phtml \ *.inc \ *.m \ *.markdown \ *.md \ *.mm \ *.dox \ *.doc \ *.txt \ *.py \ *.pyw \ *.f90 \ *.f95 \ *.f03 \ *.f08 \ *.f \ *.for \ *.tcl \ *.vhd \ *.vhdl \ *.ucf \ *.qsf \ *.ice RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = doc/ INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES SOURCE_TOOLTIPS = YES USE_HTAGS = NO VERBATIM_HEADERS = YES CLANG_ASSISTED_PARSING = NO CLANG_OPTIONS = CLANG_DATABASE_PATH = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = NO HTML_DYNAMIC_MENUS = YES HTML_DYNAMIC_SECTIONS = NO HTML_INDEX_NUM_ENTRIES = 100 GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project DOCSET_PUBLISHER_ID = org.doxygen.Publisher DOCSET_PUBLISHER_NAME = Publisher GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO GENERATE_QHP = NO QCH_FILE = QHP_NAMESPACE = org.doxygen.Project QHP_VIRTUAL_FOLDER = doc QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = QHG_LOCATION = GENERATE_ECLIPSEHELP = NO ECLIPSE_DOC_ID = org.doxygen.Project DISABLE_INDEX = NO GENERATE_TREEVIEW = NO ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES FORMULA_MACROFILE = USE_MATHJAX = NO MATHJAX_FORMAT = HTML-CSS MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ MATHJAX_EXTENSIONS = MATHJAX_CODEFILE = SEARCHENGINE = YES SERVER_BASED_SEARCH = NO EXTERNAL_SEARCH = NO SEARCHENGINE_URL = SEARCHDATA_FILE = searchdata.xml EXTERNAL_SEARCH_ID = EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = YES LATEX_OUTPUT = latex LATEX_CMD_NAME = MAKEINDEX_CMD_NAME = makeindex LATEX_MAKEINDEX_CMD = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4 EXTRA_PACKAGES = LATEX_HEADER = LATEX_FOOTER = LATEX_EXTRA_STYLESHEET = LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain LATEX_TIMESTAMP = NO LATEX_EMOJI_DIRECTORY = #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = RTF_SOURCE_CODE = NO #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_SUBDIR = MAN_LINKS = NO #--------------------------------------------------------------------------- # Configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_PROGRAMLISTING = YES XML_NS_MEMB_FILE_SCOPE = NO #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook DOCBOOK_PROGRAMLISTING = NO #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = NO INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = __attribute__(x)= EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration options related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = NO DIA_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO DOT_NUM_THREADS = 0 DOT_FONTNAME = Helvetica DOT_FONTSIZE = 10 DOT_FONTPATH = CLASS_GRAPH = NO COLLABORATION_GRAPH = NO GROUP_GRAPHS = NO UML_LOOK = NO UML_LIMIT_NUM_FIELDS = 10 TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = NO INCLUDED_BY_GRAPH = NO CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = NO DIRECTORY_GRAPH = NO DOT_IMAGE_FORMAT = png INTERACTIVE_SVG = NO DOT_PATH = DOTFILE_DIRS = MSCFILE_DIRS = DIAFILE_DIRS = PLANTUML_JAR_PATH = PLANTUML_CFG_FILE = PLANTUML_INCLUDE_PATH = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES libzpc-1.3.0/doc/references.bib000066400000000000000000000030701475140344100163450ustar00rootroot00000000000000@misc{POP, title = "{IBM} z/{A}rchitecture {P}rinciples of {O}perations, {SA}22-7832-12", year = "2019", note = "\url{https://publibfp.dhe.ibm.com/epubs/pdf/a227832c.pdf}" } @misc{AES, title = "{NIST} {FIPS} 197 - {A}nnouncing the {ADVANCED} {ENCRYPTION} {STANDARD} ({AES})", year = "2001", note = "\url{https://doi.org/10.6028/NIST.FIPS.197}" } @misc{MODES, title = "{NIST} {SP} 800-38{A} - {R}ecommendation for {B}lock {C}ipher {M}odes of {O}peration: {M}ethods and {T}echniques", year = "2001", note = "\url{https://doi.org/10.6028/NIST.SP.800-38A}" } @misc{CMAC, title = "{NIST} {SP} 800-38{B} - {R}ecommendation for {B}lock {C}ipher {M}odes of {O}peration: The {CMAC} {M}ode for {A}uthentication", year = "2005", note = "\url{https://doi.org/10.6028/NIST.SP.800-38B}" } @misc{CCM, title = "{NIST} {SP} 800-38{C} - {R}ecommendation for {B}lock {C}ipher {M}odes of {O}peration: The {CCM} {M}ode for {A}uthentication and {C}onfidentiality", year = "2004", note = "\url{https://doi.org/10.6028/NIST.SP.800-38C}" } @misc{GCM, title = "{NIST} {SP} 800-38{D} - {R}ecommendation for {B}lock {C}ipher {M}odes of {O}peration: {G}alois/{C}ounter {M}ode ({GCM}) and {GMAC}", year = "2007", note = "\url{https://doi.org/10.6028/NIST.SP.800-38D}" } @misc{XTS, title = "{NIST} {SP} 800-38{E} - {R}ecommendation for {B}lock {C}ipher {M}odes of {O}peration: The {XTS}-{AES} {M}ode for {C}onfidentiality on {S}torage {D}evices", year = "2010", note = "\url{https://doi.org/10.6028/NIST.SP.800-38E}" } libzpc-1.3.0/include/000077500000000000000000000000001475140344100144245ustar00rootroot00000000000000libzpc-1.3.0/include/zpc/000077500000000000000000000000001475140344100152205ustar00rootroot00000000000000libzpc-1.3.0/include/zpc/aes_cbc.h000066400000000000000000000066171475140344100167620ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef ZPC_AES_CBC_H # define ZPC_AES_CBC_H # ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ # endif /** * \file zpc/aes_cbc.h * * \brief AES-CBC API * * Encryption API for the Advanced Encryption Standard (AES) * block cipher \cite AES in Cipher Block Chaining (CBC) * mode of operation \cite MODES . */ # include # include struct zpc_aes_cbc; /** * Allocate a new context for an AES-CBC operation. * \param[in,out] ctx AES-CBC context * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_cbc_alloc(struct zpc_aes_cbc **ctx); /** * Set the key to be used in the context of an AES-CBC operation. * \param[in,out] ctx AES-CBC context * \param[in] key AES key * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_cbc_set_key(struct zpc_aes_cbc *ctx, struct zpc_aes_key *key); /** * Set the initialization vector to be used in the context * of an AES-CBC operation. * \param[in,out] ctx AES-CBC context * \param[in] iv 16 byte initialization vector * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_cbc_set_iv(struct zpc_aes_cbc *ctx, const unsigned char *iv); /** * Get the intermediate initialization vector to be used in the context * of an AES-CBC operation. * \param[in,out] ctx AES-CBC context * \param[out] iv application provided buffer with 16 bytes size to * receive the 16 byte intermediate iv * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_cbc_get_intermediate_iv(struct zpc_aes_cbc *ctx, unsigned char iv[16]); /** * Set the intermediate initialization vector to be used in the context * of an AES-CBC operation. An initial iv must be set before via * zpc_aes_cbc_set_iv. * \param[in,out] ctx AES-CBC context * \param[in] iv 16 byte intermediate iv * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_cbc_set_intermediate_iv(struct zpc_aes_cbc *ctx, const unsigned char iv[16]); /** * Do an AES-CBC encryption operation. * \param[in,out] ctx AES-CBC context * \param[out] ct ciphertext * \param[in] pt plaintext * \param[in] ptlen plaintext length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_cbc_encrypt(struct zpc_aes_cbc *ctx, unsigned char *ct, const unsigned char *pt, size_t ptlen); /** * Do an AES-CBC decryption operation. * \param[in,out] ctx AES-CBC context * \param[out] pt plaintext * \param[in] ct ciphertext * \param[in] ctlen ciphertext length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_cbc_decrypt(struct zpc_aes_cbc *ctx, unsigned char *pt, const unsigned char *ct, size_t ctlen); /** * Free an AES-CBC context. * \param[in,out] ctx AES-CBC context */ __attribute__((visibility("default"))) void zpc_aes_cbc_free(struct zpc_aes_cbc **ctx); # ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ # endif #endif libzpc-1.3.0/include/zpc/aes_ccm.h000066400000000000000000000063441475140344100167720ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef ZPC_AES_CCM_H # define ZPC_AES_CCM_H # ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ # endif /** * \file zpc/aes_ccm.h * * \brief AES-CCM API * * Authenticated encryption API for the Advanced Encryption Standard (AES) * block cipher \cite AES in Counter with CBC-MAC mode of operation \cite CCM . */ # include # include struct zpc_aes_ccm; /** * Allocate a new context for an AES-CCM operation. * \param[in,out] ctx AES-CCM context * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_ccm_alloc(struct zpc_aes_ccm **ctx); /** * Set the key to be used in the context of an AES-CCM operation. * \param[in,out] ctx AES-CCM context * \param[in] key AES key * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_ccm_set_key(struct zpc_aes_ccm *ctx, struct zpc_aes_key *key); /** * Set the initialization vector to be used in the context * of an AES-CCM operation. * \param[in,out] ctx AES-CCM context * \param[in] iv 7-13 byte initialization vector * \param[in] ivlen initialization vector length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_ccm_set_iv(struct zpc_aes_ccm *ctx, const unsigned char *iv, size_t ivlen); /** * Do an AES-CCM authenticated encryption operation. * \param[in,out] ctx AES-CCM context * \param[out] ct ciphertext * \param[out] mac message authentication code * \param[in] maclen message authentication code length [bytes] * \param[in] aad additional authenticated data * \param[in] aadlen additional authenticated data length [bytes] * \param[in] pt plaintext * \param[in] ptlen plaintext length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_ccm_encrypt(struct zpc_aes_ccm *ctx, unsigned char *ct, unsigned char *mac, size_t maclen, const unsigned char *aad, size_t aadlen, const unsigned char *pt, size_t ptlen); /** * Do an AES-CCM authenticated decryption operation. * \param[in,out] ctx AES-CCM context * \param[out] pt plaintext * \param[in] mac message authentication code * \param[in] maclen message authentication code length [bytes] * \param[in] aad additional authenticated data * \param[in] aadlen additional authenticated data length [bytes] * \param[in] ct ciphertext * \param[in] ctlen ciphertext length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_ccm_decrypt(struct zpc_aes_ccm *ctx, unsigned char *pt, const unsigned char *mac, size_t maclen, const unsigned char *aad, size_t aadlen, const unsigned char *ct, size_t ctlen); /** * Free an AES-CCM context. * \param[in,out] ctx AES-CCM context */ __attribute__((visibility("default"))) void zpc_aes_ccm_free(struct zpc_aes_ccm **ctx); # ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ # endif #endif libzpc-1.3.0/include/zpc/aes_cmac.h000066400000000000000000000046241475140344100171320ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef ZPC_AES_CMAC_H # define ZPC_AES_CMAC_H # ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ # endif /** * \file zpc/aes_cmac.h * * \brief AES-CMAC API * * Message authentication API for the Cipher-based Message Authentication * Code (CMAC) \cite CMAC based on the Advanced Encryption Standard (AES) * block cipher \cite AES . */ # include # include struct zpc_aes_cmac; /** * Allocate a new context for an AES-CMAC operation. * \param[in,out] ctx AES-CMAC context * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_cmac_alloc(struct zpc_aes_cmac **ctx); /** * Set the key to be used in the context of an AES-CMAC operation. * \param[in,out] ctx AES-CMAC context * \param[in] key AES key * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_cmac_set_key(struct zpc_aes_cmac *ctx, struct zpc_aes_key *key); /** * Do an AES-CMAC signing operation. * \param[in,out] ctx AES-CMAC context * \param[out] mac message authentication code * \param[in] maclen message authentication code length [bytes] * \param[in] msg message * \param[in] msglen message length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_cmac_sign(struct zpc_aes_cmac *ctx, unsigned char *mac, size_t maclen, const unsigned char *msg, size_t msglen); /** * Do an AES-CMAC verify operation. * \param[in,out] ctx AES-CMAC context * \param[in] mac message authentication code * \param[in] maclen message authentication code length [bytes] * \param[in] msg message * \param[in] msglen message length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_cmac_verify(struct zpc_aes_cmac *ctx, const unsigned char *mac, size_t maclen, const unsigned char *msg, size_t msglen); /** * Free an AES-CMAC context. * \param[in,out] ctx AES-CMAC context */ __attribute__((visibility("default"))) void zpc_aes_cmac_free(struct zpc_aes_cmac **ctx); # ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ # endif #endif libzpc-1.3.0/include/zpc/aes_ecb.h000066400000000000000000000042441475140344100167560ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef ZPC_AES_ECB_H # define ZPC_AES_ECB_H # ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ # endif /** * \file zpc/aes_ecb.h * * \brief AES-ECB API * * Encryption API for the Advanced Encryption Standard (AES) * block cipher \cite AES in Electronic Code Book (ECB) * mode of operation \cite MODES . */ # include # include struct zpc_aes_ecb; /** * Allocate a new context for an AES-ECB operation. * \param[in,out] ctx AES-ECB context * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_ecb_alloc(struct zpc_aes_ecb **ctx); /** * Set the key to be used in the context of an AES-ECB operation. * \param[in,out] ctx AES-ECB context * \param[in] key AES key * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_ecb_set_key(struct zpc_aes_ecb *ctx, struct zpc_aes_key *key); /** * Do an AES-ECB encryption operation. * \param[in,out] ctx AES-ECB context * \param[out] ct ciphertext * \param[in] pt plaintext * \param[in] ptlen plaintext length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_ecb_encrypt(struct zpc_aes_ecb *ctx, unsigned char *ct, const unsigned char *pt, size_t ptlen); /** * Do an AES-ECB decryption operation. * \param[in,out] ctx AES-ECB context * \param[out] pt plaintext * \param[in] ct ciphertext * \param[in] ctlen ciphertext length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_ecb_decrypt(struct zpc_aes_ecb *ctx, unsigned char *pt, const unsigned char *ct, size_t ctlen); /** * Free an AES-ECB context. * \param[in,out] ctx AES-ECB context */ __attribute__((visibility("default"))) void zpc_aes_ecb_free(struct zpc_aes_ecb **ctx); # ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ # endif #endif libzpc-1.3.0/include/zpc/aes_gcm.h000066400000000000000000000074271475140344100170010ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef ZPC_AES_GCM_H # define ZPC_AES_GCM_H # ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ # endif /** * \file zpc/aes_gcm.h * * \brief AES-GCM API * * Authenticated encryption API for the Advanced Encryption Standard (AES) * block cipher \cite AES in Galois/Counter Mode mode of operation \cite GCM . */ # include # include struct zpc_aes_gcm; /** * Allocate a new context for an AES-GCM operation. * \param[in,out] ctx AES-GCM context * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_gcm_alloc(struct zpc_aes_gcm **ctx); /** * Set the key to be used in the context of an AES-GCM operation. * \param[in,out] ctx AES-GCM context * \param[in] key AES key * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_gcm_set_key(struct zpc_aes_gcm *ctx, struct zpc_aes_key *key); /** * Create the initialization vector to be used in the context * of an AES-GCM operation. The minimum and recommended iv length is 12 bytes. * \param[in,out] ctx AES-GCM context * \param[in/out] iv application provided buffer of at least ivlen bytes to * receive the internally created initialization vector * \param[in] ivlen initialization vector length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_gcm_create_iv(struct zpc_aes_gcm *ctx, unsigned char *iv, size_t ivlen); /** * Set the initialization vector to be used in the context * of an AES-GCM operation. * \param[in,out] ctx AES-GCM context * \param[in] iv initialization vector * \param[in] ivlen initialization vector length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_gcm_set_iv(struct zpc_aes_gcm *ctx, const unsigned char *iv, size_t ivlen); /** * Do an AES-GCM authenticated encryption operation. * \param[in,out] ctx AES-GCM context * \param[out] ct ciphertext * \param[out] mac message authentication code * \param[in] maclen message authentication code length [bytes] * \param[in] aad additional authenticated data * \param[in] aadlen additional authenticated data length [bytes] * \param[in] pt plaintext * \param[in] ptlen plaintext length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_gcm_encrypt(struct zpc_aes_gcm *ctx, unsigned char *ct, unsigned char *mac, size_t maclen, const unsigned char *aad, size_t aadlen, const unsigned char *pt, size_t ptlen); /** * Do an AES-GCM authenticated decryption operation. * \param[in,out] ctx AES-GCM context * \param[out] pt plaintext * \param[in] mac message authentication code * \param[in] maclen message authentication code length [bytes] * \param[in] aad additional authenticated data * \param[in] aadlen additional authenticated data length [bytes] * \param[in] ct ciphertext * \param[in] ctlen ciphertext length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_gcm_decrypt(struct zpc_aes_gcm *ctx, unsigned char *pt, const unsigned char *mac, size_t maclen, const unsigned char *aad, size_t aadlen, const unsigned char *ct, size_t ctlen); /** * Free an AES-CCM context. * \param[in,out] ctx AES-GCM context */ __attribute__((visibility("default"))) void zpc_aes_gcm_free(struct zpc_aes_gcm **ctx); # ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ # endif #endif libzpc-1.3.0/include/zpc/aes_key.h000066400000000000000000000116251475140344100170160ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef ZPC_AES_KEY_H # define ZPC_AES_KEY_H # ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ # endif /** * \file zpc/aes_key.h * \brief AES key API. * * Manage advanced Encryption Standard (AES) block cipher * \cite AES keys. */ # include /* * These constants match with kernel's pkey.h, enum pkey_key_type. */ # define ZPC_AES_KEY_TYPE_CCA_DATA 1 # define ZPC_AES_KEY_TYPE_CCA_CIPHER 2 # define ZPC_AES_KEY_TYPE_EP11 3 # define ZPC_AES_KEY_TYPE_PVSECRET 9 # define ZPC_AES_KEY_REENCIPHER_OLD_TO_CURRENT 1 # define ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW 2 typedef enum { ZPC_AES_SECRET_TYPE_NOT_SET = -2, ZPC_AES_SECRET_TYPE_INVALID = -1, ZPC_AES_SECRET_AES_128 = 0x04, /* architected key types, also below */ ZPC_AES_SECRET_AES_192 = 0x05, ZPC_AES_SECRET_AES_256 = 0x06, } zpc_aessecret_type_t; struct zpc_aes_key; /** * Allocate a new AES key object with reference count 1. * \param[in,out] key AES key * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_key_alloc(struct zpc_aes_key **key); /** * Set the AES key size. * \param[in,out] key AES key * \param[in] size 128, 192 or 256 bit key size * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_key_set_size(struct zpc_aes_key *key, int size); /** * Set the AES key type. * \param[in,out] key AES key * \param[in] type ZPC_AES_KEY_TYPE_CCA_DATA, ZPC_AES_KEY_TYPE_CCA_CIPHER, * ZPC_AES_KEY_TYPE_EP11, or ZPC_AES_KEY_TYPE_PVSECRET * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_key_set_type(struct zpc_aes_key *key, int type); /** * Set the AES key flags. * \param[in,out] key AES key * \param[in] flags key flags * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_key_set_flags(struct zpc_aes_key *key, unsigned int flags); /** * Set the AES key Master Key Verification Pattern. * \param[in,out] key AES key * \param[in] mkvp master key verification pattern * This function has no effect for keys of type PVSECRET. * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_key_set_mkvp(struct zpc_aes_key *key, const char *mkvp); /** * Set the AES key APQNs * \param[in,out] key AES key * \param[in] apqns NULL-terminated APQN list * This function has no effect for keys of type PVSECRET. * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_key_set_apqns(struct zpc_aes_key *key, const char *apqns[]); /** * Import an AES secure-key. * \param[in,out] key AES key * \param[in] seckey AES secure-key * \param[in] seckeylen AES key secure-length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_key_import(struct zpc_aes_key *key, const unsigned char *seckey, size_t seckeylen); /** * Import an AES clear-key. * \param[in,out] key AES key * \param[in] clearkey AES clear-key * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_key_import_clear(struct zpc_aes_key *key, const unsigned char *clrkey); /** * Export an AES secure-key. * \param[in,out] key AES key * \param[out] seckey AES secure-key * \param[in,out] seckeylen secure AES secure-key length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_key_export(struct zpc_aes_key *key, unsigned char *seckey, size_t *seckeylen); /** * Generate an AES secure-key. * \param[in,out] key AES key * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_key_generate(struct zpc_aes_key *key); /** * Reencipher an AES secure-key. * \param[in,out] key AES key * \param[in] reenc ZPC_AES_KEY_REENCIPHER_OLD_TO_CURRENT * or ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW * This function is not applicable for keys of type PVSECRET and returns * ZPC_ERROR_KEYTYPE when called for such keys. * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_key_reencipher(struct zpc_aes_key *key, int reenc); /** * Decrease the reference count of an AES key object * and free it the count reaches 0. * \param[in,out] key AES key */ __attribute__((visibility("default"))) void zpc_aes_key_free(struct zpc_aes_key **key); # ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ # endif #endif libzpc-1.3.0/include/zpc/aes_xts.h000066400000000000000000000067711475140344100170520ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef ZPC_AES_XTS_H # define ZPC_AES_XTS_H # ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ # endif /** * \file zpc/aes_xts.h * * \brief AES-XTS API * * Encryption API for the Advanced Encryption Standard (AES) * block cipher \cite AES in XEX-based Tweaked-codebook mode with * ciphertext Stealing (XTS) mode of operation \cite XTS . */ # include # include struct zpc_aes_xts; /** * Allocate a new context for an AES-XTS operation. * \param[in,out] ctx AES-XTS context * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_xts_alloc(struct zpc_aes_xts **ctx); /** * Set the key to be used in the context of an AES-XTS operation. * \param[in,out] ctx AES-XTS context * \param[in] key1 first AES key * \param[in] key2 second AES key * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_xts_set_key(struct zpc_aes_xts *ctx, struct zpc_aes_key *key1, struct zpc_aes_key *key2); /** * Set the initialization vector to be used in the context * of an AES-XTS operation. * \param[in,out] ctx AES-XTS context * \param[in] iv 16 byte initialization vector * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_xts_set_iv(struct zpc_aes_xts *ctx, const unsigned char *iv); /** * Get the intermediate initialization vector to be used in the context * of an AES-XTS operation. * \param[in,out] ctx AES-XTS context * \param[out] iv application provided buffer with 16 bytes size to * receive the 16 byte intermediate iv * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_xts_get_intermediate_iv(struct zpc_aes_xts *ctx, unsigned char iv[16]); /** * Set the intermediate initialization vector to be used in the context * of an AES-XTS operation. An initial iv must be set before via * zpc_aes_xts_set_iv. * \param[in,out] ctx AES-XTS context * \param[in] iv 16 byte intermediate iv * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_xts_set_intermediate_iv(struct zpc_aes_xts *ctx, const unsigned char iv[16]); /** * Do an AES-XTS encryption operation. * \param[in,out] ctx AES-XTS context * \param[out] ct ciphertext * \param[in] pt plaintext * \param[in] ptlen plaintext length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_xts_encrypt(struct zpc_aes_xts *ctx, unsigned char *ct, const unsigned char *pt, size_t ptlen); /** * Do an AES-XTS decryption operation. * \param[in,out] ctx AES-XTS context * \param[out] pt plaintext * \param[in] ct ciphertext * \param[in] ctlen ciphertext length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_aes_xts_decrypt(struct zpc_aes_xts *ctx, unsigned char *pt, const unsigned char *ct, size_t ctlen); /** * Free an AES-XTS context. * \param[in,out] ctx AES-XTS context */ __attribute__((visibility("default"))) void zpc_aes_xts_free(struct zpc_aes_xts **ctx); # ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ # endif #endif libzpc-1.3.0/include/zpc/ecc_key.h000066400000000000000000000165721475140344100170060ustar00rootroot00000000000000/* * Copyright IBM Corp. 2022 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef ZPC_ECC_KEY_H # define ZPC_ECC_KEY_H # ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ # endif /** * \file zpc/ecc_key.h * \brief ECC key API. * * Manage elliptic curve cryptography (ECC) cipher * \cite EC keys. */ #include /* * These constants match with kernel's pkey.h, enum pkey_key_type. */ #define ZPC_EC_KEY_TYPE_CCA 0x1f #define ZPC_EC_KEY_TYPE_EP11 7 #define ZPC_EC_KEY_TYPE_PVSECRET 9 #define ZPC_EC_KEY_REENCIPHER_OLD_TO_CURRENT 1 #define ZPC_EC_KEY_REENCIPHER_CURRENT_TO_NEW 2 typedef enum { ZPC_EC_CURVE_NOT_SET = -2, ZPC_EC_CURVE_INVALID = -1, ZPC_EC_CURVE_P256 = 0, ZPC_EC_CURVE_P384, ZPC_EC_CURVE_P521, ZPC_EC_CURVE_ED25519, ZPC_EC_CURVE_ED448 } zpc_ec_curve_t; typedef enum { ZPC_EC_SECRET_TYPE_NOT_SET = -2, ZPC_EC_SECRET_TYPE_INVALID = -1, ZPC_EC_SECRET_ECDSA_P256 = 0x0011, /* architected key types, also below */ ZPC_EC_SECRET_ECDSA_P384 = 0x0012, ZPC_EC_SECRET_ECDSA_P521 = 0x0013, ZPC_EC_SECRET_EDDSA_ED25519 = 0x0014, ZPC_EC_SECRET_EDDSA_ED448 = 0x0015, } zpc_ecsecret_type_t; struct zpc_ec_key; /** * Allocate a new EC key object with reference count 1. * \param[in,out] key EC key * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ec_key_alloc(struct zpc_ec_key **key); /** * Set the EC curve. * \param[in,out] key EC key * \param[in] curve EC curve * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ec_key_set_curve(struct zpc_ec_key *key, zpc_ec_curve_t curve); /** * Set the EC key type. * \param[in,out] key EC key * \param[in] type ZPC_EC_KEY_TYPE_CCA or ZPC_EC_KEY_TYPE_EP11 * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ec_key_set_type(struct zpc_ec_key *key, int type); /** * Set the EC key flags. * \param[in,out] key EC key * \param[in] flags key flags * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ec_key_set_flags(struct zpc_ec_key *key, unsigned int flags); /** * Set the EC key Master Key Verification Pattern. * \param[in,out] key EC key * \param[in] mkvp master key verification pattern (8 bytes for CCA keys, 16 * or 32 bytes for EP11 keys, only the first 16 bytes are relevant). * This function has no effect for keys of type PVSECRET. * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ec_key_set_mkvp(struct zpc_ec_key *key, const char *mkvp); /** * Set the EC key APQNs * \param[in,out] key EC key * \param[in] apqns NULL-terminated APQN list * This function has no effect for keys of type PVSECRET. * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ec_key_set_apqns(struct zpc_ec_key *key, const char *apqns[]); /** * Import an EC secure-key. Depending on the key type (CCA or EP11), the secure * key buffer must contain either a CCA secure key token or an EP11 secure key * structure. For EP11 type keys, a SubjectPublicKeyInfo encoding (SPKI) of * the related public EC key may be appended to the secure key data. * * \param[in,out] key EC key * \param[in] seckey EC secure-key * \param[in] seckeylen EC key secure-length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ec_key_import(struct zpc_ec_key *key, const unsigned char *seckey, unsigned int seckeylen); /** * Import an EC clear-key pair. At least one of the key parts must be non-NULL. * A NULL key part leaves a previously set key part untouched, so it is e.g. * possible to first import a secure key using the zpc_ec_key_import() * function, and then adding the corresponding public key with a subsequent * zpc_ec_import_clear() call. * No integrity check is performed on the imported key material, except of a * plausibility check on the length of the provided key parts. The * application is responsible for providing valid key parts or pairs. * Public keys are considered to be the concatenated X and Y values without * a leading 0x04 byte that would indicate an uncompressed public key. * For PVSECRET type keys it is possible to add the public key to the key object * by importing the clear public key. The privkey parm must be NULL and privlen * must be 0 when doing this. * \param[in,out] key EC key * \param[in] pubkey an uncompressed EC public key (can be NULL) * \param[in] publen EC public key length [bytes] * \param[in] privkey EC private key (can be NULL) * \param[in] privlen EC private key length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ec_key_import_clear(struct zpc_ec_key *key, const unsigned char *pubkey, unsigned int publen, const unsigned char *privkey, unsigned int privlen); /** * Export an EC secure-key. Depending on the key type (CCA or EP11), the secure * key is either a CCA secure key token or an EP11 secure key structure. For * EP11 type keys, a SubjectPublicKeyInfo encoding (SPKI) of the related public * EC key is appended to the secure key data if the key object has a public key. * * \param[in,out] key EC key * \param[out] seckey EC secure-key * \param[in,out] seckeylen secure EC secure-key length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ec_key_export(struct zpc_ec_key *key, unsigned char *seckey, unsigned int *seckeylen); /** * Export an EC public-key. * \param[in,out] key EC key * \param[out] pubkey uncompressed EC public-key (can be NULL to obtain * the length only) * The output buffer contains the concatenated X and Y values of the public key * without a leading byte indicating an uncompressed key. * \param[in,out] pubkeylen EC public-key length [bytes] * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ec_key_export_public(struct zpc_ec_key *key, unsigned char *pubkey, unsigned int *pubkeylen); /** * Generate an EC secure-key. * \param[in,out] key EC key * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ec_key_generate(struct zpc_ec_key *key); /** * Reencipher an EC secure-key. * \param[in,out] key EC key * \param[in] reenc ZPC_EC_KEY_REENCIPHER_OLD_TO_CURRENT * or ZPC_EC_KEY_REENCIPHER_CURRENT_TO_NEW * This function is not applicable for pvsecret-type keys and returns * ZPC_ERROR_KEYTYPE when called for such keys. * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ec_key_reencipher(struct zpc_ec_key *key, unsigned int reenc); /** * Decrease the reference count of an EC key object * and free it the count reaches 0. * \param[in,out] key EC key */ __attribute__((visibility("default"))) void zpc_ec_key_free(struct zpc_ec_key **key); # ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ # endif #endif libzpc-1.3.0/include/zpc/ecdsa_ctx.h000066400000000000000000000051231475140344100173270ustar00rootroot00000000000000/* * Copyright IBM Corp. 2022 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef ZPC_ECDSA_CTX_H # define ZPC_ECDSA_CTX_H # ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ # endif /** * \file zpc/ecdsa_ctx.h * * \brief ECDSA-CTX API * * Sign/verify API for elliptic curve cryptography (ECDSA) algorithms. * \cite ECDSA sign/verify */ # include # include struct zpc_ecdsa_ctx; /** * Allocate a new context for an ECDSA sign/verify operation. * \param[in,out] ctx ECDSA context * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ecdsa_ctx_alloc(struct zpc_ecdsa_ctx **ctx); /** * Set the key to be used in the context of an ECDSA sign/verify operation. * \param[in,out] ctx ECDSA context * \param[in] key EC key * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ecdsa_ctx_set_key(struct zpc_ecdsa_ctx *ctx, struct zpc_ec_key *key); /** * Do an ECDSA sign operation. * \param[in,out] ctx ECDSA context * \param[in] hash input message to sign * \param[in] hash_len input message length [bytes] * \param[out] signature signature * \param[in,out] *sig_len address of signature length field [bytes] * On input, the application must specify the buffer length * to receive the signature [bytes]. If signature is NULL, * only the length of the signature is returned. * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ecdsa_sign(struct zpc_ecdsa_ctx *ctx, const unsigned char *hash, unsigned int hash_len, unsigned char *signature, unsigned int *sig_len); /** * Do an ECDSA verify operation. * \param[in,out] ctx ECDSA context * \param[in] hash input message to verify * \param[in] hash_len input message length [bytes] * \param[in] signature signature to verify * \param[in] sig_len signature length * \return 0 on success. Otherwise, a non-zero error code is returned. */ __attribute__((visibility("default"))) int zpc_ecdsa_verify(struct zpc_ecdsa_ctx *ctx, const unsigned char *hash, unsigned int hash_len, const unsigned char *signature, unsigned int sig_len); /** * Free an ECDSA context. * \param[in,out] ctx ECDSA context */ __attribute__((visibility("default"))) void zpc_ecdsa_ctx_free(struct zpc_ecdsa_ctx **ctx); # ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ # endif #endif libzpc-1.3.0/include/zpc/error.h000066400000000000000000000254431475140344100165320ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef ZPC_ERROR_H # define ZPC_ERROR_H # ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ # endif /** * \file zpc/error.h * \brief Error API. */ /** * \def ZPC_ERROR_ARG1NULL * \brief Function argument 1 is NULL. */ # define ZPC_ERROR_ARG1NULL 1 /** * \def ZPC_ERROR_ARG2NULL * \brief Function argument 2 is NULL. */ # define ZPC_ERROR_ARG2NULL 2 /** * \def ZPC_ERROR_ARG3NULL * \brief Function argument 3 is NULL. */ # define ZPC_ERROR_ARG3NULL 3 /** * \def ZPC_ERROR_ARG4NULL * \brief Function argument 4 is NULL. */ # define ZPC_ERROR_ARG4NULL 4 /** * \def ZPC_ERROR_ARG5NULL * \brief Function argument 5 is NULL. */ # define ZPC_ERROR_ARG5NULL 5 /** * \def ZPC_ERROR_ARG6NULL * \brief Function argument 6 is NULL. */ # define ZPC_ERROR_ARG6NULL 6 /** * \def ZPC_ERROR_ARG7NULL * \brief Function argument 7 is NULL. */ # define ZPC_ERROR_ARG7NULL 7 /** * \def ZPC_ERROR_ARG8NULL * \brief Function argument 8 is NULL. */ # define ZPC_ERROR_ARG8NULL 8 /** * \def ZPC_ERROR_ARG1RANGE * \brief Function argument 1 is out of range. */ # define ZPC_ERROR_ARG1RANGE 9 /** * \def ZPC_ERROR_ARG2RANGE * \brief Function argument 2 is out of range. */ # define ZPC_ERROR_ARG2RANGE 10 /** * \def ZPC_ERROR_ARG3RANGE * \brief Function argument 3 is out of range. */ # define ZPC_ERROR_ARG3RANGE 11 /** * \def ZPC_ERROR_ARG4RANGE * \brief Function argument 4 is out of range. */ # define ZPC_ERROR_ARG4RANGE 12 /** * \def ZPC_ERROR_ARG5RANGE * \brief Function argument 5 is out of range. */ # define ZPC_ERROR_ARG5RANGE 13 /** * \def ZPC_ERROR_ARG6RANGE * \brief Function argument 6 is out of range. */ # define ZPC_ERROR_ARG6RANGE 14 /** * \def ZPC_ERROR_ARG7RANGE * \brief Function argument 7 is out of range. */ # define ZPC_ERROR_ARG7RANGE 15 /** * \def ZPC_ERROR_ARG8RANGE * \brief Function argument 8 is out of range. */ # define ZPC_ERROR_ARG8RANGE 16 /** * \def ZPC_ERROR_MALLOC * \brief Malloc failed. */ # define ZPC_ERROR_MALLOC 17 /** * \def ZPC_ERROR_KEYNOTSET * \brief Key not set. */ # define ZPC_ERROR_KEYNOTSET 18 /** * \def ZPC_ERROR_KEYSIZE * \brief Invalid key size. */ # define ZPC_ERROR_KEYSIZE 19 /** * \def ZPC_ERROR_IVNOTSET * \brief IV not set. */ # define ZPC_ERROR_IVNOTSET 20 /** * \def ZPC_ERROR_IVSIZE * \brief Invalid IV size. */ # define ZPC_ERROR_IVSIZE 21 /** * \def ZPC_ERROR_TAGSIZE * \brief Invalid tag size. */ # define ZPC_ERROR_TAGSIZE 22 /** * \def ZPC_ERROR_TAGMISMATCH * \brief Tag mismatch. */ # define ZPC_ERROR_TAGMISMATCH 23 /** * \def ZPC_ERROR_HWCAPS * \brief Function not supported. */ # define ZPC_ERROR_HWCAPS 24 /** * \def ZPC_ERROR_SMALLOUTBUF * \brief Output buffer too small. */ # define ZPC_ERROR_SMALLOUTBUF 25 /** * \def ZPC_ERROR_APQNSNOTSET * \brief APQNs not set. */ # define ZPC_ERROR_APQNSNOTSET 26 /** * \def ZPC_ERROR_KEYTYPE * \brief Invalid key type. */ # define ZPC_ERROR_KEYTYPE 27 /** * \def ZPC_ERROR_KEYTYPENOTSET * \brief Key type not set. */ # define ZPC_ERROR_KEYTYPENOTSET 28 /** * \def ZPC_ERROR_IOCTLGENSECK2 * \brief PKEY_GENSECK2 ioctl failed. */ # define ZPC_ERROR_IOCTLGENSECK2 29 /** * \def ZPC_ERROR_IOCTLCLR2SECK2 * \brief PKEY_CLR2SECK2 ioctl failed. */ # define ZPC_ERROR_IOCTLCLR2SECK2 30 /** * \def ZPC_ERROR_IOCTLBLOB2PROTK2 * \brief PKEY_BLOB2PROTK2 ioctl failed. */ # define ZPC_ERROR_IOCTLBLOB2PROTK2 31 /** * \def ZPC_ERROR_WKVPMISMATCH * \brief Wrapping key verification pattern mismatch. */ # define ZPC_ERROR_WKVPMISMATCH 32 /** * \def ZPC_ERROR_DEVPKEY * \brief Opening /dev/pkey failed. */ # define ZPC_ERROR_DEVPKEY 33 /** * \def ZPC_ERROR_CLEN * \brief Ciphertext too long. */ # define ZPC_ERROR_CLEN 34 /** * \def ZPC_ERROR_MLEN * \brief Message too long. */ # define ZPC_ERROR_MLEN 35 /** * \def ZPC_ERROR_AADLEN * \brief Additional authenticated data too long. */ # define ZPC_ERROR_AADLEN 36 /** * \def ZPC_ERROR_PARSE * \brief Parse error. */ # define ZPC_ERROR_PARSE 38 /** * \def ZPC_ERROR_APQNNOTFOUND * \brief APQN not found in APQN list. */ # define ZPC_ERROR_APQNNOTFOUND 39 /** * \def ZPC_ERROR_MKVPLEN * \brief MKVP too long. */ # define ZPC_ERROR_MKVPLEN 40 /** * \def ZPC_ERROR_INITLOCK * \brief Initializing a lock failed. */ # define ZPC_ERROR_INITLOCK 42 /** * \def ZPC_ERROR_OBJINUSE * \brief Object is in use. */ # define ZPC_ERROR_OBJINUSE 43 /** * \def ZPC_ERROR_IOCTLAPQNS4KT * \brief PKEY_APQNS4KT ioctl failed. */ # define ZPC_ERROR_IOCTLAPQNS4KT 44 /** * \def ZPC_ERROR_KEYSIZENOTSET * \brief Key-size not set. */ # define ZPC_ERROR_KEYSIZENOTSET 45 /** * \def ZPC_ERROR_IOCTLGENPROTK * \brief PKEY_GENPROTK ioctl failed. */ # define ZPC_ERROR_IOCTLGENPROTK 46 /** * \def ZPC_ERROR_PROTKEYONLY * \brief Protected-key only. */ # define ZPC_ERROR_PROTKEYONLY 47 /** * \def ZPC_ERROR_KEYSEQUAL * \brief Keys are equal. */ # define ZPC_ERROR_KEYSEQUAL 48 /** * \def ZPC_ERROR_NOTSUP * \brief Not supported. */ # define ZPC_ERROR_NOTSUP 49 /** * \def ZPC_ERROR_EC_INVALID_CURVE * \brief Invalid EC curve. */ # define ZPC_ERROR_EC_INVALID_CURVE 50 /** * \def ZPC_ERROR_EC_CURVE_NOTSET * \brief EC curve not set. */ # define ZPC_ERROR_EC_CURVE_NOTSET 51 /** * \def ZPC_ERROR_EC_PRIVKEY_NOTSET * \brief EC private key not set. */ # define ZPC_ERROR_EC_PRIVKEY_NOTSET 52 /** * \def ZPC_ERROR_EC_PUBKEY_NOTSET * \brief EC public key not set. */ # define ZPC_ERROR_EC_PUBKEY_NOTSET 53 /** * \def ZPC_ERROR_EC_NO_KEY_PARTS * \brief No EC key parts given. */ # define ZPC_ERROR_EC_NO_KEY_PARTS 54 /** * \def ZPC_ERROR_EC_SIGNATURE_INVALID * \brief signature invalid. */ # define ZPC_ERROR_EC_SIGNATURE_INVALID 55 /** * \def ZPC_ERROR_IOCTLBLOB2PROTK3 * \brief PKEY_BLOB2PROTK3 ioctl failed. */ # define ZPC_ERROR_IOCTLBLOB2PROTK3 56 /** * \def ZPC_ERROR_IOCTLCLR2SECK3 * \brief PKEY_CLR2SECK3 ioctl failed. */ # define ZPC_ERROR_IOCTLCLR2SECK3 57 /** * \def ZPC_ERROR_APQNS_NOTSET * \brief No APQNs set for this key, but required for this operation. */ # define ZPC_ERROR_APQNS_NOTSET 58 /** * \def ZPC_ERROR_EC_SIGNATURE_LENGTH * \brief length of given signature is invalid for this EC key. */ # define ZPC_ERROR_EC_SIGNATURE_LENGTH 59 /** * \def ZPC_ERROR_EC_KEY_PARTS_INCONSISTENT * \brief given public/private key parts are inconsistent. They do not belong * to the same EC key. */ # define ZPC_ERROR_EC_KEY_PARTS_INCONSISTENT 60 /** * \def ZPC_ERROR_CCA_HOST_LIB_NOT_AVAILABLE * \brief the CCA host library is not available, but required for this function. */ # define ZPC_ERROR_CCA_HOST_LIB_NOT_AVAILABLE 61 /** * \def ZPC_ERROR_EP11_HOST_LIB_NOT_AVAILABLE * \brief the EP11 host library is not available, but required for this function. */ # define ZPC_ERROR_EP11_HOST_LIB_NOT_AVAILABLE 62 /** * \def ZPC_ERROR_EC_PUBKEY_LENGTH * \brief the given EC public key length is invalid. */ # define ZPC_ERROR_EC_PUBKEY_LENGTH 63 /** * \def ZPC_ERROR_EC_PRIVKEY_LENGTH * \brief the given EC private key length is invalid. */ # define ZPC_ERROR_EC_PRIVKEY_LENGTH 64 /** * \def ZPC_ERROR_EC_NO_CCA_SECUREKEY_TOKEN * \brief the given buffer does not contain a valid CCA secure key token. */ # define ZPC_ERROR_EC_NO_CCA_SECUREKEY_TOKEN 65 /** * \def ZPC_ERROR_EC_NO_EP11_SECUREKEY_TOKEN * \brief the given buffer does not contain a valid EP11 secure key token. */ # define ZPC_ERROR_EC_NO_EP11_SECUREKEY_TOKEN 66 /** * \def ZPC_ERROR_EC_EP11_SPKI_INVALID_LENGTH * \brief the imported buffer contains an EP11 SPKI with an invalid length. */ # define ZPC_ERROR_EC_EP11_SPKI_INVALID_LENGTH 67 /** * \def ZPC_ERROR_EC_EP11_SPKI_INVALID_FOR_CURVE * \brief the imported buffer contains an EP11 SPKI with an invalid EC curve. */ # define ZPC_ERROR_EC_EP11_SPKI_INVALID_CURVE 68 /** * \def ZPC_ERROR_EC_EP11_SPKI_INVALID_FOR_PUBKEY * \brief the imported buffer contains an EP11 SPKI with an invalid public key. */ # define ZPC_ERROR_EC_EP11_SPKI_INVALID_PUBKEY 69 /** * \def ZPC_ERROR_EC_EP11_SPKI_INVALID_MKVP * \brief the imported buffer contains an EP11 MACed SPKI with an invalid MKVP. */ # define ZPC_ERROR_EC_EP11_SPKI_INVALID_MKVP 70 /** * \def ZPC_ERROR_BLOB_NOT_PKEY_EXTRACTABLE * \brief the imported buffer contains a key blob that cannot be transformed into a protected key. */ # define ZPC_ERROR_BLOB_NOT_PKEY_EXTRACTABLE 71 /** * \def ZPC_ERROR_APQNS_INVALID_VERSION * \brief At least one APQN version is invalid for this function. */ # define ZPC_ERROR_APQNS_INVALID_VERSION 72 /** * \def ZPC_ERROR_AES_NO_EP11_SECUREKEY_TOKEN * \brief the given buffer does not contain a valid EP11 AES secure key token. */ # define ZPC_ERROR_AES_NO_EP11_SECUREKEY_TOKEN 73 /** * \def ZPC_ERROR_AES_NO_CCA_DATAKEY_TOKEN * \brief the given buffer does not contain a valid CCA datakey token. */ # define ZPC_ERROR_AES_NO_CCA_DATAKEY_TOKEN 74 /** * \def ZPC_ERROR_AES_NO_CCA_CIPHERKEY_TOKEN * \brief the given buffer does not contain a valid CCA cipherkey token. */ # define ZPC_ERROR_AES_NO_CCA_CIPHERKEY_TOKEN 75 /** * \def ZPC_ERROR_RNDGEN * \brief error creating random bytes. */ # define ZPC_ERROR_RNDGEN 76 /** * \def ZPC_ERROR_GCM_IV_CREATED_INTERNALLY * \brief invalid usage of a gcm context with an internally created iv. */ # define ZPC_ERROR_GCM_IV_CREATED_INTERNALLY 77 /** * \def ZPC_ERROR_UV_PVSECRETS_NOT_AVAILABLE * \brief support for UV retrievable secrets is not available, but required for this function. */ # define ZPC_ERROR_UV_PVSECRETS_NOT_AVAILABLE 78 /** * \def ZPC_ERROR_PVSECRET_TYPE_NOT_SUPPORTED * \brief the given pvsecret type is not supported by libzpc. */ # define ZPC_ERROR_PVSECRET_TYPE_NOT_SUPPORTED 79 /** * \def ZPC_ERROR_PVSECRET_ID_NOT_FOUND_IN_UV * \brief the given pvsecret ID does not belong to a secret on this system. */ # define ZPC_ERROR_PVSECRET_ID_NOT_FOUND_IN_UV 80 /** * \def ZPC_ERROR_IOCTLVERIFYKEY2 * \brief PKEY_VERIFYKEY2 ioctl failed. */ # define ZPC_ERROR_IOCTLVERIFYKEY2 81 /** * \fn const char *zpc_error_string(int err) * \brief Map an error code to the corresponding error string. * \param[in] err An error code. * \return A pointer to an error string. */ __attribute__((visibility("default"))) const char *zpc_error_string(int); # ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ # endif #endif libzpc-1.3.0/libzpc.map000066400000000000000000000032321475140344100147630ustar00rootroot00000000000000ZPC_1.0 { global: zpc_error_string; zpc_aes_key_alloc; zpc_aes_key_set_size; zpc_aes_key_set_type; zpc_aes_key_set_flags; zpc_aes_key_set_mkvp; zpc_aes_key_set_apqns; zpc_aes_key_import_clear; zpc_aes_key_import; zpc_aes_key_export; zpc_aes_key_generate; zpc_aes_key_reencipher; zpc_aes_key_free; zpc_aes_ecb_alloc; zpc_aes_ecb_set_key; zpc_aes_ecb_encrypt; zpc_aes_ecb_decrypt; zpc_aes_ecb_free; zpc_aes_cbc_alloc; zpc_aes_cbc_set_key; zpc_aes_cbc_set_iv; zpc_aes_cbc_encrypt; zpc_aes_cbc_decrypt; zpc_aes_cbc_free; zpc_aes_xts_alloc; zpc_aes_xts_set_key; zpc_aes_xts_set_iv; zpc_aes_xts_encrypt; zpc_aes_xts_decrypt; zpc_aes_xts_free; zpc_aes_cmac_alloc; zpc_aes_cmac_set_key; zpc_aes_cmac_sign; zpc_aes_cmac_verify; zpc_aes_cmac_free; zpc_aes_ccm_alloc; zpc_aes_ccm_set_key; zpc_aes_ccm_set_iv; zpc_aes_ccm_encrypt; zpc_aes_ccm_decrypt; zpc_aes_ccm_free; zpc_aes_gcm_alloc; zpc_aes_gcm_set_key; zpc_aes_gcm_set_iv; zpc_aes_gcm_encrypt; zpc_aes_gcm_decrypt; zpc_aes_gcm_free; local: *; }; ZPC_1.1.0 { global: zpc_ec_key_alloc; zpc_ec_key_set_curve; zpc_ec_key_set_type; zpc_ec_key_set_flags; zpc_ec_key_set_mkvp; zpc_ec_key_set_apqns; zpc_ec_key_import; zpc_ec_key_import_clear; zpc_ec_key_export; zpc_ec_key_export_public; zpc_ec_key_generate; zpc_ec_key_reencipher; zpc_ec_key_free; zpc_ecdsa_ctx_alloc; zpc_ecdsa_ctx_set_key; zpc_ecdsa_sign; zpc_ecdsa_verify; zpc_ecdsa_ctx_free; local: *; } ZPC_1.0; ZPC_1.2.0 { global: zpc_aes_xts_get_intermediate_iv; zpc_aes_xts_set_intermediate_iv; zpc_aes_cbc_get_intermediate_iv; zpc_aes_cbc_set_intermediate_iv; zpc_aes_gcm_create_iv; local: *; } ZPC_1.1.0; libzpc-1.3.0/libzpc.pc.in000066400000000000000000000003621475140344100152160ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ Name: @PROJECT_NAME@ Description: @PROJECT_DESCRIPTION@ Version: @PROJECT_VERSION@ libzpc-1.3.0/libzpc.spec000066400000000000000000000060531475140344100151440ustar00rootroot00000000000000Name: libzpc Version: 1.3.0 Release: 1%{?dist} Summary: Open Source library for the IBM Z Protected-key crypto feature License: MIT Url: https://github.com/opencryptoki/libzpc Source0: %{url}/archive/v%{version}/%{name}-%{version}.tar.gz ExclusiveArch: s390x BuildRequires: cmake BuildRequires: gcc BuildRequires: g++ BuildRequires: make BuildRequires: json-c-devel #Additional prerequisites for building the test program: libjson-c devel #Additional prereqs for building the html and latex doc: doxygen >= 1.8.17, latex, bibtex # Be explicit about the soversion in order to avoid unintentional changes. %global soversion 1 %description The IBM Z Protected-key Crypto library libzpc is an open-source library targeting the 64-bit Linux on IBM Z (s390x) platform. It provides interfaces for cryptographic primitives. The underlying implementations make use of z/Architecture's extensive performance-boosting hardware support and its protected-key feature which ensures that key material is never present in main memory at any time. %package devel Summary: Development files for %{name} Requires: %{name}%{?_isa} = %{version}-%{release} %description devel The %{name}-devel package contains libraries and header files for developing applications that use %{name}. %package static Summary: Static library version %{name} Requires: %{name}-devel%{?_isa} = %{version}-%{release} %description static The %{name}-static package contains the static library of %{name}. %prep %autosetup %{name}-%{version} # The following options can be passed to cmake: # -DCMAKE_INSTALL_PREFIX= : # Change the install prefix from `/usr/local/` to ``. # -DCMAKE_BUILD_TYPE= : Choose predefined build options. # The choices for `` are `Debug`, `Release`, `RelWithDebInfo`, # and `MinSizeRel`. # -DBUILD_SHARED_LIBS=ON : Build a shared object (instead of an archive). # -DBUILD_TEST=ON : Build the test program. # -DBUILD_DOC=ON : Build the html and latex doc. %build %cmake %cmake_build %install %cmake_install %check %ctest %files %doc README.md CHANGES.md %license LICENSE %{_libdir}/%{name}.so.%{soversion}* %files devel %{_includedir}/zpc/ %{_libdir}/pkgconfig/%{name}.pc %{_libdir}/%{name}.so %files static %{_libdir}/%{name}.a %changelog * Fri Feb 07 2025 Joerg Schmidbauer - 1.3.0 - Support for UV retrievable secrets. * Thu Dec 07 2023 Joerg Schmidbauer - 1.2.0 - Support for get/set intermediate iv for CBC and XTS. - Support for internal iv for GCM. * Fri Sep 15 2023 Joerg Schmidbauer - 1.1.1 - Exploit PKEY_KBLOB2PROTK2 for AES EP11 version 6 keys. * Thu Feb 02 2023 Joerg Schmidbauer - 1.1.0 - Support for ECC keys and ECDSA signatures. * Wed Jun 22 2022 Joerg Schmidbauer - 1.0.1 - Updated spec file for rpm build and changed location of pkgconfig file to libdir. * Mon Feb 21 2022 Joerg Schmidbauer - 1.0.0 - Initial version based on libzpc provided by Patrick Steuer, libzpc-1.3.0/misc/000077500000000000000000000000001475140344100137345ustar00rootroot00000000000000libzpc-1.3.0/misc/nist2json_aes_cbc.pl000077500000000000000000000043751475140344100176750ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; my ($out, $fdout) = ("nist_aes_cbc.json"); my ($state, $i, $first) = (0, 0, 1); my ($bufpre, $buf, $bufpost) = ("", "", ""); my ($in, $fdin, $line); my ($keylen) = (undef); my ($count, $countre) = ("", '^COUNT = (\d+)'); my ($key, $keyre) = ("", '^KEY = ([0-9a-f]*)'); my ($iv, $ivre) = ("", '^IV = ([0-9a-f]*)'); my ($ct, $ctre) = ("", '^CIPHERTEXT = ([0-9a-f]*)'); my ($pt, $ptre) = ("", '^PLAINTEXT = ([0-9a-f]*)'); sub print_begin_tests { $buf .= ",\n" if ($first != 1); $buf .= <<__; { "ivSize" : 128, "keySize" : $keylen, "tests" : [ __ $keylen = undef; $first = 0; } sub print_test { $buf .= ",\n" if ($state == 2); $buf .= <<__; { "tcId" : $i, "comment" : "$count", "key" : "$key", "iv" : "$iv", "msg" : "$pt", "ct" : "$ct" __ $buf .= " }"; $i = $i + 1; $key = ""; $iv = ""; $ct = ""; $pt = ""; } sub print_end_tests { $buf .= "\n ]\n"; $buf .= " }"; } printf("Parsing NIST AES-CBC test vectors ...\n"); for (@ARGV) { $in=$_; open($fdin, '<', $in) || die("ERROR: couldn't open $in ($!)."); $keylen = 128 if ($in =~ /128/); $keylen = 192 if ($in =~ /192/); $keylen = 256 if ($in =~ /256/); print_begin_tests(); $state = 0; while ($line = <$fdin>) { chomp($line); $key = $1 if ($line =~ /$keyre/); $iv = $1 if ($line =~ /$ivre/); $ct = $1 if ($line =~ /$ctre/); $pt = $1 if ($line =~ /$ptre/); if ($state == 0 && $line =~ /$countre/) { $state = 1; next; } if ($state == 1 && $line =~ /$countre/) { print_test(); $state = 2; next; } if ($state == 2 && $line =~ /$countre/) { print_test(); next; } } print_test(); print_end_tests(); close($fdin); } $bufpre = <<__; { "algorithm" : "AES-CBC", "numberOfTests" : $i, "testGroups" : [ __ $bufpost = "\n ]\n}"; $buf = $bufpre . $buf . $bufpost; # Expect 60 printf("$i test vectors found.\n"); open($fdout, '>', $out) || die("ERROR: couldn't open $out ($!)."); print({$fdout}$buf); close($fdout); libzpc-1.3.0/misc/nist2json_aes_ecb.pl000077500000000000000000000041541475140344100176720ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; my ($out, $fdout) = ("nist_aes_ecb.json"); my ($state, $i, $first) = (0, 0, 1); my ($bufpre, $buf, $bufpost) = ("", "", ""); my ($in, $fdin, $line); my ($keylen) = (undef); my ($count, $countre) = ("", '^COUNT = (\d+)'); my ($key, $keyre) = ("", '^KEY = ([0-9a-f]*)'); my ($ct, $ctre) = ("", '^CIPHERTEXT = ([0-9a-f]*)'); my ($pt, $ptre) = ("", '^PLAINTEXT = ([0-9a-f]*)'); sub print_begin_tests { $buf .= ",\n" if ($first != 1); $buf .= <<__; { "keySize" : $keylen, "tests" : [ __ $keylen = undef; $first = 0; } sub print_test { $buf .= ",\n" if ($state == 2); $buf .= <<__; { "tcId" : $i, "comment" : "$count", "key" : "$key", "msg" : "$pt", "ct" : "$ct" __ $buf .= " }"; $i = $i + 1; $key = ""; $ct = ""; $pt = ""; } sub print_end_tests { $buf .= "\n ]\n"; $buf .= " }"; } printf("Parsing NIST AES-CBC test vectors ...\n"); for (@ARGV) { $in=$_; open($fdin, '<', $in) || die("ERROR: couldn't open $in ($!)."); $keylen = 128 if ($in =~ /128/); $keylen = 192 if ($in =~ /192/); $keylen = 256 if ($in =~ /256/); print_begin_tests(); $state = 0; while ($line = <$fdin>) { chomp($line); $key = $1 if ($line =~ /$keyre/); $ct = $1 if ($line =~ /$ctre/); $pt = $1 if ($line =~ /$ptre/); if ($state == 0 && $line =~ /$countre/) { $state = 1; next; } if ($state == 1 && $line =~ /$countre/) { print_test(); $state = 2; next; } if ($state == 2 && $line =~ /$countre/) { print_test(); next; } } print_test(); print_end_tests(); close($fdin); } $bufpre = <<__; { "algorithm" : "AES-ECB", "numberOfTests" : $i, "testGroups" : [ __ $bufpost = "\n ]\n}"; $buf = $bufpre . $buf . $bufpost; # Expect 60 printf("$i test vectors found.\n"); open($fdout, '>', $out) || die("ERROR: couldn't open $out ($!)."); print({$fdout}$buf); close($fdout); libzpc-1.3.0/misc/nist2json_aes_gcm.pl000077500000000000000000000072451475140344100177130ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; my ($out, $fdout) = ("nist_aes_gcm.json"); my ($state, $i, $j) = (0, 0, 0); my ($bufpre, $buf, $bufpost, $deconly) = ("", "", "", ""); my ($in, $fdin, $line); my ($keylen, $keylenre) = (undef, '^\[Keylen = (128|192|256)\]'); my ($ivlen, $ivlenre) = (undef, '^\[IVlen = (\d+)\]'); my ($ptlen, $ptlenre) = (undef, '^\[PTlen = (\d+)\]'); my ($aadlen, $aadlenre) = (undef, '^\[AADlen = (\d+)\]'); my ($taglen, $taglenre) = (undef, '^\[Taglen = (\d+)\]'); my ($count, $countre) = ("", '^Count = (\d+)'); my ($key, $keyre) = ("", '^Key = ([0-9a-f]*)'); my ($iv, $ivre) = ("", '^IV = ([0-9a-f]*)'); my ($ct, $ctre) = ("", '^CT = ([0-9a-f]*)'); my ($aad, $aadre) = ("", '^AAD = ([0-9a-f]*)'); my ($tag, $tagre) = ("", '^Tag = ([0-9a-f]*)'); my ($pt, $ptre) = ("", '^PT = ([0-9a-f]*)'); my ($result, $resultre) = ("valid", '^FAIL'); sub print_begin_tests { $buf .= ",\n" if ($state != 0); $buf .= <<__; { "ivSize" : $ivlen, "keySize" : $keylen, "tagSize" : $taglen, "tests" : [ __ $keylen = undef; $ivlen = undef; $taglen = undef; $ptlen = undef; $aadlen = undef; } sub print_test { $buf .= ",\n" if ($state != 1); $buf .= <<__; { "tcId" : $i, "comment" : "$count", "key" : "$key", "iv" : "$iv", "aad" : "$aad", "msg" : "$pt", "ct" : "$ct", "tag" : "$tag", "result" : "$result", "flags" : [$deconly] __ $buf .= " }"; $i = $i + 1; $key = ""; $iv = ""; $ct = ""; $aad = ""; $tag = ""; $pt = ""; $result = "valid"; } sub print_end_tests { $buf .= "\n ]\n"; $buf .= " }"; } printf("Parsing NIST AES-GCM test vectors ...\n"); for (@ARGV) { $in=$_; open($fdin, '<', $in) || die("ERROR: couldn't open $in ($!)."); if ($in =~ /Decrypt/) { $deconly = "\"DecryptOnly\""; } else { $deconly = ""; } while ($line = <$fdin>) { chomp($line); $keylen = $1 if ($line =~ /$keylenre/); $ivlen = $1 if ($line =~ /$ivlenre/); $taglen = $1 if ($line =~ /$taglenre/); $ptlen = $1 if ($line =~ /$ptlenre/); $aadlen = $1 if ($line =~ /$aadlenre/); $key = $1 if ($line =~ /$keyre/); $iv = $1 if ($line =~ /$ivre/); $ct = $1 if ($line =~ /$ctre/); $aad = $1 if ($line =~ /$aadre/); $tag = $1 if ($line =~ /$tagre/); $pt = $1 if ($line =~ /$ptre/); $result ="invalid" if ($line =~ /$resultre/); if ($state == 0 && $line =~ /$countre/) { print_begin_tests(); $state = 1; $j = $j + 1; next; } if ($state == 1 && $line =~ /$countre/) { print_test(); $state = 2; $j = $j + 1; next; } if ($state == 2 && $line =~ /$countre/) { print_test(); $j = $j + 1; next; } if ($state == 2 && $line =~ /$keylenre/) { print_test(); $state = 3; next; } if ($state == 3 && $line =~ /$countre/) { print_end_tests(); print_begin_tests(); $state = 1; $j = $j + 1; next; } } close($fdin); } print_test(); print_end_tests(); $bufpre = <<__; { "algorithm" : "AES-GCM", "numberOfTests" : $i, "testGroups" : [ __ $bufpost = "\n ]\n}"; $buf = $bufpre . $buf . $bufpost; # Expect 47250 printf("$i test vectors found.\n"); if ($i != $j) { die ("ERROR: expected $j test vectors"); } open($fdout, '>', $out) || die("ERROR: couldn't open $out ($!)."); print({$fdout}$buf); close($fdout); libzpc-1.3.0/misc/nist2json_aes_xts.pl000077500000000000000000000045001475140344100177520ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; my ($out, $fdout) = ("nist_aes_xts.json"); my ($state, $i, $first) = (0, 0, 1); my ($bufpre, $buf, $bufpost) = ("", "", ""); my ($in, $fdin, $line); my ($keylen) = (undef); my ($count, $countre) = ("", '^COUNT = (\d+)'); my ($bits, $bitsre) = ("", '^DataUnitLen = (\d+)'); my ($key, $keyre) = ("", '^Key = ([0-9a-f]*)'); my ($iv, $ivre) = ("", '^i = ([0-9a-f]*)'); my ($pt, $ptre) = ("", '^PT = ([0-9a-f]*)'); my ($ct, $ctre) = ("", '^CT = ([0-9a-f]*)'); sub print_begin_tests { $buf .= ",\n" if ($first != 1); $buf .= <<__; { "keySize" : $keylen, "tests" : [ __ $keylen = undef; $first = 0; } sub print_test { return if ($bits % 8 != 0); $buf .= ",\n" if ($state == 2); $buf .= <<__; { "tcId" : $i, "comment" : "$count", "key" : "$key", "iv" : "$iv", "msg" : "$pt", "ct" : "$ct" __ $buf .= " }"; $i = $i + 1; $bits = "", $key = ""; $iv=""; $ct = ""; $pt = ""; } sub print_end_tests { $buf .= "\n ]\n"; $buf .= " }"; } printf("Parsing NIST AES-XTS test vectors ...\n"); for (@ARGV) { $in=$_; open($fdin, '<', $in) || die("ERROR: couldn't open $in ($!)."); $keylen = 128 if ($in =~ /128/); $keylen = 256 if ($in =~ /256/); print_begin_tests(); $state = 0; while ($line = <$fdin>) { chomp($line); $bits = $1 if ($line =~ /$bitsre/); $key = $1 if ($line =~ /$keyre/); $iv = $1 if ($line =~ /$ivre/); $ct = $1 if ($line =~ /$ctre/); $pt = $1 if ($line =~ /$ptre/); if ($state == 0 && $line =~ /$countre/) { $state = 1; next; } if ($state == 1 && $line =~ /$countre/) { print_test(); $state = 2; next; } if ($state == 2 && $line =~ /$countre/) { print_test(); next; } } print_test(); print_end_tests(); close($fdin); } $bufpre = <<__; { "algorithm" : "AES-XTS", "numberOfTests" : $i, "testGroups" : [ __ $bufpost = "\n ]\n}"; $buf = $bufpre . $buf . $bufpost; # Expect 60 printf("$i test vectors found.\n"); open($fdout, '>', $out) || die("ERROR: couldn't open $out ($!)."); print({$fdout}$buf); close($fdout); libzpc-1.3.0/misc/nist2json_ecdsa.pl000066400000000000000000000046631475140344100173720ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; my ($out, $fdout) = ("nist_ecdsa.json"); my ($state, $i, $first) = (0, 0, 1); my ($bufpre, $buf, $bufpost) = ("", "", ""); my ($in, $fdin, $line); my ($curve, $curvere) = ("", '^\[([A-Z]-[0-9][0-9][0-9]*)'); my ($msg, $msgre) = ("", '^Msg = ([0-9a-f]*)'); my ($priv_d, $priv_dre) = ("", '^d = ([0-9a-f]*)'); my ($pub_x, $pub_xre) = ("", '^Qx = ([0-9a-f]*)'); my ($pub_y, $pub_yre) = ("", '^Qy = ([0-9a-f]*)'); my ($rand_k, $rand_kre) = ("", '^k = ([0-9a-f]*)'); my ($sig_r, $sig_rre) = ("", '^R = ([0-9a-f]*)'); my ($sig_s, $sig_sre) = ("", '^S = ([0-9a-f]*)'); sub print_begin_tests { $buf .= ",\n" if ($first != 1); $buf .= <<__; { "tests" : [ __ $first = 0; } sub print_test { $buf .= <<__; { "tcId" : $i, "curve" : "$curve", "msg" : "$msg", "d" : "$priv_d", "x" : "$pub_x", "y" : "$pub_y", "sig_r" : "$sig_r", "sig_s" : "$sig_s" __ $buf .= " },"; $i = $i + 1; $msg = ""; $priv_d = ""; $pub_x = ""; $pub_y = ""; $sig_r = ""; $sig_s = ""; } sub print_end_tests { $buf .= "\n ]\n"; $buf .= " }"; } printf("Parsing NIST ECDSA test vectors ...\n"); for (@ARGV) { $in=$_; open($fdin, '<', $in) || die("ERROR: couldn't open $in ($!)."); print_begin_tests(); $state = 0; while ($line = <$fdin>) { chomp($line); $curve = $1 if ($line =~ /$curvere/); $msg = $1 if ($line =~ /$msgre/); $priv_d = $1 if ($line =~ /$priv_dre/); $pub_x = $1 if ($line =~ /$pub_xre/); $pub_y = $1 if ($line =~ /$pub_yre/); $rand_k = $1 if ($line =~ /$rand_kre/); $sig_r = $1 if ($line =~ /$sig_rre/); $sig_s = $1 if ($line =~ /$sig_sre/); if ($state == 0 && $line =~ /$msgre/) { $state = 1; next; } if ($state == 1 && $line =~ /$sig_sre/) { print_test() if ($curve eq "P-256" || $curve eq "P-384" || $curve eq "P-521"); $state = 0; next; } } print_end_tests(); close($fdin); } $bufpre = <<__; { "algorithm" : "ECDSA", "numberOfTests" : $i, "testGroups" : [ __ $bufpost = "\n ]\n}"; $buf = $bufpre . $buf . $bufpost; # Expect 150 printf("$i test vectors found.\n"); open($fdout, '>', $out) || die("ERROR: couldn't open $out ($!)."); print({$fdout}$buf); close($fdout); libzpc-1.3.0/misc/nist_eddsa.json000066400000000000000000000276101475140344100167520ustar00rootroot00000000000000{ "algorithm" : "ECDSA", "numberOfTests" : 13, "testGroups" : [ { "tests" : [ { "tcId" : 0, "curve" : "ed25519", "msg" : "", "priv" : "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", "pub" : "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", "sig" : "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b", }, { "tcId" : 1, "curve" : "ed25519", "msg" : "72", "priv" : "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", "pub" : "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", "sig" : "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00", }, { "tcId" : 2, "curve" : "ed25519", "msg" : "af82", "priv" : "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7", "pub" : "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025", "sig" : "6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a" }, { "tcId" : 3, "curve" : "ed25519", "msg" : "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "priv" : "833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42", "pub" : "ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf", "sig" : "dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b58909351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704" }, { "tcId" : 4, "curve" : "ed25519", "msg" : "08b8b2b733424243760fe426a4b54908632110a66c2f6591eabd3345e3e4eb98fa6e264bf09efe12ee50f8f54e9f77b1e355f6c50544e23fb1433ddf73be84d879de7c0046dc4996d9e773f4bc9efe5738829adb26c81b37c93a1b270b20329d658675fc6ea534e0810a4432826bf58c941efb65d57a338bbd2e26640f89ffbc1a858efcb8550ee3a5e1998bd177e93a7363c344fe6b199ee5d02e82d522c4feba15452f80288a821a579116ec6dad2b3b310da903401aa62100ab5d1a36553e06203b33890cc9b832f79ef80560ccb9a39ce767967ed628c6ad573cb116dbefefd75499da96bd68a8a97b928a8bbc103b6621fcde2beca1231d206be6cd9ec7aff6f6c94fcd7204ed3455c68c83f4a41da4af2b74ef5c53f1d8ac70bdcb7ed185ce81bd84359d44254d95629e9855a94a7c1958d1f8ada5d0532ed8a5aa3fb2d17ba70eb6248e594e1a2297acbbb39d502f1a8c6eb6f1ce22b3de1a1f40cc24554119a831a9aad6079cad88425de6bde1a9187ebb6092cf67bf2b13fd65f27088d78b7e883c8759d2c4f5c65adb7553878ad575f9fad878e80a0c9ba63bcbcc2732e69485bbc9c90bfbd62481d9089beccf80cfe2df16a2cf65bd92dd597b0707e0917af48bbb75fed413d238f5555a7a569d80c3414a8d0859dc65a46128bab27af87a71314f318c782b23ebfe808b82b0ce26401d2e22f04d83d1255dc51addd3b75a2b1ae0784504df543af8969be3ea7082ff7fc9888c144da2af58429ec96031dbcad3dad9af0dcbaaaf268cb8fcffead94f3c7ca495e056a9b47acdb751fb73e666c6c655ade8297297d07ad1ba5e43f1bca32301651339e22904cc8c42f58c30c04aafdb038dda0847dd988dcda6f3bfd15c4b4c4525004aa06eeff8ca61783aacec57fb3d1f92b0fe2fd1a85f6724517b65e614ad6808d6f6ee34dff7310fdc82aebfd904b01e1dc54b2927094b2db68d6f903b68401adebf5a7e08d78ff4ef5d63653a65040cf9bfd4aca7984a74d37145986780fc0b16ac451649de6188a7dbdf191f64b5fc5e2ab47b57f7f7276cd419c17a3ca8e1b939ae49e488acba6b965610b5480109c8b17b80e1b7b750dfc7598d5d5011fd2dcc5600a32ef5b52a1ecc820e308aa342721aac0943bf6686b64b2579376504ccc493d97e6aed3fb0f9cd71a43dd497f01f17c0e2cb3797aa2a2f256656168e6c496afc5fb93246f6b1116398a346f1a641f3b041e989f7914f90cc2c7fff357876e506b50d334ba77c225bc307ba537152f3f1610e4eafe595f6d9d90d11faa933a15ef1369546868a7f3a45a96768d40fd9d03412c091c6315cf4fde7cb68606937380db2eaaa707b4c4185c32eddcdd306705e4dc1ffc872eeee475a64dfac86aba41c0618983f8741c5ef68d3a101e8a3b8cac60c905c15fc910840b94c00a0b9d0", "priv" : "f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5", "pub" : "278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e", "sig" : "0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03" }, { "tcId" : 5, "curve" : "ed448", "msg" : "", "priv" : "6c82a562cb808d10d632be89c8513ebf6c929f34ddfa8c9f63c9960ef6e348a3528c8a3fcc2f044e39a3fc5b94492f8f032e7549a20098f95b", "pub" : "5fd7449b59b461fd2ce787ec616ad46a1da1342485a70e1f8a0ea75d80e96778edf124769b46c7061bd6783df1e50f6cd1fa1abeafe8256180", "sig" : "533a37f6bbe457251f023c0d88f976ae2dfb504a843e34d2074fd823d41a591f2b233f034f628281f2fd7a22ddd47d7828c59bd0a21bfd3980ff0d2028d4b18a9df63e006c5d1c2d345b925d8dc00b4104852db99ac5c7cdda8530a113a0f4dbb61149f05a7363268c71d95808ff2e652600" }, { "tcId" : 6, "curve" : "ed448", "msg" : "03", "priv" : "c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e", "pub" : "43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480", "sig" : "26b8f91727bd62897af15e41eb43c377efb9c610d48f2335cb0bd0087810f4352541b143c4b981b7e18f62de8ccdf633fc1bf037ab7cd779805e0dbcc0aae1cbcee1afb2e027df36bc04dcecbf154336c19f0af7e0a6472905e799f1953d2a0ff3348ab21aa4adafd1d234441cf807c03a00" }, { "tcId" : 7, "curve" : "ed448", "msg" : "0c3e544074ec63b0265e0c", "priv" : "cd23d24f714274e744343237b93290f511f6425f98e64459ff203e8985083ffdf60500553abc0e05cd02184bdb89c4ccd67e187951267eb328", "pub" : "dcea9e78f35a1bf3499a831b10b86c90aac01cd84b67a0109b55a36e9328b1e365fce161d71ce7131a543ea4cb5f7e9f1d8b00696447001400", "sig" : "1f0a8888ce25e8d458a21130879b840a9089d999aaba039eaf3e3afa090a09d389dba82c4ff2ae8ac5cdfb7c55e94d5d961a29fe0109941e00b8dbdeea6d3b051068df7254c0cdc129cbe62db2dc957dbb47b51fd3f213fb8698f064774250a5028961c9bf8ffd973fe5d5c206492b140e00" }, { "tcId" : 8, "curve" : "ed448", "msg" : "64a65f3cdedcdd66811e2915", "priv" : "258cdd4ada32ed9c9ff54e63756ae582fb8fab2ac721f2c8e676a72768513d939f63dddb55609133f29adf86ec9929dccb52c1c5fd2ff7e21b", "pub" : "3ba16da0c6f2cc1f30187740756f5e798d6bc5fc015d7c63cc9510ee3fd44adc24d8e968b6e46e6f94d19b945361726bd75e149ef09817f580", "sig" : "7eeeab7c4e50fb799b418ee5e3197ff6bf15d43a14c34389b59dd1a7b1b85b4ae90438aca634bea45e3a2695f1270f07fdcdf7c62b8efeaf00b45c2c96ba457eb1a8bf075a3db28e5c24f6b923ed4ad747c3c9e03c7079efb87cb110d3a99861e72003cbae6d6b8b827e4e6c143064ff3c00" }, { "tcId" : 9, "curve" : "ed448", "msg" : "64a65f3cdedcdd66811e2915e7", "priv" : "7ef4e84544236752fbb56b8f31a23a10e42814f5f55ca037cdcc11c64c9a3b2949c1bb60700314611732a6c2fea98eebc0266a11a93970100e", "pub" : "b3da079b0aa493a5772029f0467baebee5a8112d9d3a22532361da294f7bb3815c5dc59e176b4d9f381ca0938e13c6c07b174be65dfa578e80", "sig" : "6a12066f55331b6c22acd5d5bfc5d71228fbda80ae8dec26bdd306743c5027cb4890810c162c027468675ecf645a83176c0d7323a2ccde2d80efe5a1268e8aca1d6fbc194d3f77c44986eb4ab4177919ad8bec33eb47bbb5fc6e28196fd1caf56b4e7e0ba5519234d047155ac727a1053100" }, { "tcId" : 10, "curve" : "ed448", "msg" : "bd0f6a3747cd561bdddf4640a332461a4a30a12a434cd0bf40d766d9c6d458e5512204a30c17d1f50b5079631f64eb3112182da3005835461113718d1a5ef944", "priv" : "d65df341ad13e008567688baedda8e9dcdc17dc024974ea5b4227b6530e339bff21f99e68ca6968f3cca6dfe0fb9f4fab4fa135d5542ea3f01", "pub" : "df9705f58edbab802c7f8363cfe5560ab1c6132c20a9f1dd163483a26f8ac53a39d6808bf4a1dfbd261b099bb03b3fb50906cb28bd8a081f00", "sig" : "554bc2480860b49eab8532d2a533b7d578ef473eeb58c98bb2d0e1ce488a98b18dfde9b9b90775e67f47d4a1c3482058efc9f40d2ca033a0801b63d45b3b722ef552bad3b4ccb667da350192b61c508cf7b6b5adadc2c8d9a446ef003fb05cba5f30e88e36ec2703b349ca229c2670833900" }, { "tcId" : 11, "curve" : "ed448", "msg" : "15777532b0bdd0d1389f636c5f6b9ba734c90af572877e2d272dd078aa1e567cfa80e12928bb542330e8409f3174504107ecd5efac61ae7504dabe2a602ede89e5cca6257a7c77e27a702b3ae39fc769fc54f2395ae6a1178cab4738e543072fc1c177fe71e92e25bf03e4ecb72f47b64d0465aaea4c7fad372536c8ba516a6039c3c2a39f0e4d832be432dfa9a706a6e5c7e19f397964ca4258002f7c0541b590316dbc5622b6b2a6fe7a4abffd96105eca76ea7b98816af0748c10df048ce012d901015a51f189f3888145c03650aa23ce894c3bd889e030d565071c59f409a9981b51878fd6fc110624dcbcde0bf7a69ccce38fabdf86f3bef6044819de11", "priv" : "2ec5fe3c17045abdb136a5e6a913e32ab75ae68b53d2fc149b77e504132d37569b7e766ba74a19bd6162343a21c8590aa9cebca9014c636df5", "pub" : "79756f014dcfe2079f5dd9e718be4171e2ef2486a08f25186f6bff43a9936b9bfe12402b08ae65798a3d81e22e9ec80e7690862ef3d4ed3a00", "sig" : "c650ddbb0601c19ca11439e1640dd931f43c518ea5bea70d3dcde5f4191fe53f00cf966546b72bcc7d58be2b9badef28743954e3a44a23f880e8d4f1cfce2d7a61452d26da05896f0a50da66a239a8a188b6d825b3305ad77b73fbac0836ecc60987fd08527c1a8e80d5823e65cafe2a3d00" }, { "tcId" : 12, "curve" : "ed448", "msg" : "6ddf802e1aae4986935f7f981ba3f0351d6273c0a0c22c9c0e8339168e675412a3debfaf435ed651558007db4384b650fcc07e3b586a27a4f7a00ac8a6fec2cd86ae4bf1570c41e6a40c931db27b2faa15a8cedd52cff7362c4e6e23daec0fbc3a79b6806e316efcc7b68119bf46bc76a26067a53f296dafdbdc11c77f7777e972660cf4b6a9b369a6665f02e0cc9b6edfad136b4fabe723d2813db3136cfde9b6d044322fee2947952e031b73ab5c603349b307bdc27bc6cb8b8bbd7bd323219b8033a581b59eadebb09b3c4f3d2277d4f0343624acc817804728b25ab797172b4c5c21a22f9c7839d64300232eb66e53f31c723fa37fe387c7d3e50bdf9813a30e5bb12cf4cd930c40cfb4e1fc622592a49588794494d56d24ea4b40c89fc0596cc9ebb961c8cb10adde976a5d602b1c3f85b9b9a001ed3c6a4d3b1437f52096cd1956d042a597d561a596ecd3d1735a8d570ea0ec27225a2c4aaff26306d1526c1af3ca6d9cf5a2c98f47e1c46db9a33234cfd4d81f2c98538a09ebe76998d0d8fd25997c7d255c6d66ece6fa56f11144950f027795e653008f4bd7ca2dee85d8e90f3dc315130ce2a00375a318c7c3d97be2c8ce5b6db41a6254ff264fa6155baee3b0773c0f497c573f19bb4f4240281f0b1f4f7be857a4e59d416c06b4c50fa09e1810ddc6b1467baeac5a3668d11b6ecaa901440016f389f80acc4db977025e7f5924388c7e340a732e554440e76570f8dd71b7d640b3450d1fd5f0410a18f9a3494f707c717b79b4bf75c98400b096b21653b5d217cf3565c9597456f70703497a078763829bc01bb1cbc8fa04eadc9a6e3f6699587a9e75c94e5bab0036e0b2e711392cff0047d0d6b05bd2a588bc109718954259f1d86678a579a3120f19cfb2963f177aeb70f2d4844826262e51b80271272068ef5b3856fa8535aa2a88b2d41f2a0e2fda7624c2850272ac4a2f561f8f2f7a318bfd5caf9696149e4ac824ad3460538fdc25421beec2cc6818162d06bbed0c40a387192349db67a118bada6cd5ab0140ee273204f628aad1c135f770279a651e24d8c14d75a6059d76b96a6fd857def5e0b354b27ab937a5815d16b5fae407ff18222c6d1ed263be68c95f32d908bd895cd76207ae726487567f9a67dad79abec316f683b17f2d02bf07e0ac8b5bc6162cf94697b3c27cd1fea49b27f23ba2901871962506520c392da8b6ad0d99f7013fbc06c2c17a569500c8a7696481c1cd33e9b14e40b82e79a5f5db82571ba97bae3ad3e0479515bb0e2b0f3bfcd1fd33034efc6245eddd7ee2086ddae2600d8ca73e214e8c2b0bdb2b047c6a464a562ed77b73d2d841c4b34973551257713b753632efba348169abc90a68f42611a40126d7cb21b58695568186f7e569d2ff0f9e745d0487dd2eb997cafc5abf9dd102e62ff66cba87", "priv" : "872d093780f5d3730df7c212664b37b8a0f24f56810daa8382cd4fa3f77634ec44dc54f1c2ed9bea86fafb7632d8be199ea165f5ad55dd9ce8", "pub" : "a81b2e8a70a5ac94ffdbcc9badfc3feb0801f258578bb114ad44ece1ec0e799da08effb81c5d685c0c56f64eecaef8cdf11cc38737838cf400", "sig" : "e301345a41a39a4d72fff8df69c98075a0cc082b802fc9b2b6bc503f926b65bddf7f4c8f1cb49f6396afc8a70abe6d8aef0db478d4c6b2970076c6a0484fe76d76b3a97625d79f1ce240e7c576750d295528286f719b413de9ada3e8eb78ed573603ce30d8bb761785dc30dbc320869e1a00" }, ] } ] } libzpc-1.3.0/src/000077500000000000000000000000001475140344100135705ustar00rootroot00000000000000libzpc-1.3.0/src/aes_cbc.c000066400000000000000000000240051475140344100153140ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include "zpc/aes_cbc.h" #include "zpc/error.h" #include "aes_cbc_local.h" #include "aes_key_local.h" #include "cpacf.h" #include "globals.h" #include "misc.h" #include "debug.h" #include "zkey/pkey.h" #include #include #include #include #include static void __aes_cbc_set_iv(struct zpc_aes_cbc *, const u8 iv[16]); static int __aes_cbc_crypt(struct zpc_aes_cbc *, u8 *, const u8 *, size_t, unsigned long); static void __aes_cbc_reset(struct zpc_aes_cbc *); static void __aes_cbc_reset_iv(struct zpc_aes_cbc *); int zpc_aes_cbc_alloc(struct zpc_aes_cbc **aes_cbc) { struct zpc_aes_cbc *new_aes_cbc = NULL; int rc; if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.aes_cbc) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_cbc == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } new_aes_cbc = calloc(1, sizeof(*new_aes_cbc)); if (new_aes_cbc == NULL) { rc = ZPC_ERROR_MALLOC; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } DEBUG("aes-cbc context at %p: allocated", new_aes_cbc); *aes_cbc = new_aes_cbc; rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_cbc_set_key(struct zpc_aes_cbc *aes_cbc, struct zpc_aes_key *aes_key) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.aes_cbc) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_cbc == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("aes-cbc context at %p: key unset", aes_cbc); __aes_cbc_reset(aes_cbc); rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); rc = aes_key_check(aes_key); if (rc) goto ret; if (aes_cbc->aes_key == aes_key) { DEBUG("aes-cbc context at %p: key at %p already set", aes_cbc, aes_key); rc = 0; /* nothing to do */ goto ret; } aes_key->refcount++; DEBUG("aes key at %p: refcount %llu", aes_key, aes_key->refcount); if (aes_cbc->key_set) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("aes-cbc context at %p: key unset", aes_cbc); __aes_cbc_reset(aes_cbc); } /* Set new key. */ assert(!aes_cbc->key_set); DEBUG("aes-cbc context at %p: key at %p set", aes_cbc, aes_key); memcpy(aes_cbc->param.protkey, aes_key->prot.protkey, sizeof(aes_cbc->param.protkey)); aes_cbc->fc = CPACF_KMC_ENCRYPTED_AES_128 + (aes_key->keysize - 128) / 64; aes_cbc->aes_key = aes_key; aes_cbc->key_set = 1; rc = 0; ret: rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_cbc_set_iv(struct zpc_aes_cbc *aes_cbc, const u8 * iv) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_cbc) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_cbc == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if (iv == NULL) { /* Unset iv */ DEBUG("aes-cbc context at %p: iv unset", aes_cbc); __aes_cbc_reset_iv(aes_cbc); aes_cbc->iv_set = 0; rc = 0; goto ret; } if (aes_cbc->key_set != 1) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } __aes_cbc_set_iv(aes_cbc, iv); DEBUG("aes-cbc context at %p: iv set", aes_cbc); aes_cbc->iv_set = 1; rc = 0; ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_cbc_get_intermediate_iv(struct zpc_aes_cbc *aes_cbc, unsigned char iv[16]) { int rc; if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_cbc) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_cbc == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if (iv == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } if (aes_cbc->iv_set != 1) { rc = ZPC_ERROR_IVNOTSET; goto ret; } memcpy(iv, aes_cbc->param.cv, 16); rc = 0; ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_cbc_set_intermediate_iv(struct zpc_aes_cbc *aes_cbc, const unsigned char iv[16]) { int rc; if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_cbc) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_cbc == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if (iv == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } if (aes_cbc->key_set != 1) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } if (aes_cbc->iv_set != 1) { rc = ZPC_ERROR_IVNOTSET; goto ret; } __aes_cbc_set_iv(aes_cbc, iv); DEBUG("aes-cbc context at %p: intermediate iv set", aes_cbc); aes_cbc->iv_set = 1; rc = 0; ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_cbc_encrypt(struct zpc_aes_cbc *aes_cbc, u8 * c, const u8 * m, size_t mlen) { struct cpacf_kmc_aes_param *param; struct pkey_protkey *protkey; unsigned long flags = 0; int rc, rv, i; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_cbc) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_cbc == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if ((mlen > 0 || m != NULL) && c == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } if ((mlen > 0 || c != NULL) && m == NULL) { rc = ZPC_ERROR_ARG3NULL; goto ret; } if (mlen % 16 != 0) { rc = ZPC_ERROR_MLEN; goto ret; } if (!aes_cbc->key_set) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } if (!aes_cbc->iv_set) { rc = ZPC_ERROR_IVNOTSET; goto ret; } rc = -1; for (i = 0; i < 2 && rc != 0; i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_cbc->aes_key->prot; param = &aes_cbc->param; for (;;) { rc = __aes_cbc_crypt(aes_cbc, c, m, mlen, flags); if (rc == 0) { break; } else { if (aes_cbc->aes_key->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_cbc->aes_key->lock); assert(rv == 0); DEBUG ("aes-cbc context at %p: re-derive protected key from %s secure key from aes key at %p", aes_cbc, i == 0 ? "current" : "old", aes_cbc->aes_key); rc = aes_key_sec2prot(aes_cbc->aes_key, i); memcpy(param->protkey, protkey->protkey, sizeof(param->protkey)); rv = pthread_mutex_unlock(&aes_cbc->aes_key->lock); assert(rv == 0); } if (rc) break; } } } ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_cbc_decrypt(struct zpc_aes_cbc *aes_cbc, u8 * m, const u8 * c, size_t clen) { struct cpacf_kmc_aes_param *param; struct pkey_protkey *protkey; unsigned long flags = CPACF_M; /* decrypt */ int rc, rv, i; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_cbc) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_cbc == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if ((clen > 0 || c != NULL) && m == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } if ((clen > 0 || m != NULL) && c == NULL) { rc = ZPC_ERROR_ARG3NULL; goto ret; } if (clen % 16 != 0) { rc = ZPC_ERROR_CLEN; goto ret; } if (!aes_cbc->key_set) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } if (!aes_cbc->iv_set) { rc = ZPC_ERROR_IVNOTSET; goto ret; } rc = -1; for (i = 0; i < 2 && rc != 0; i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_cbc->aes_key->prot; param = &aes_cbc->param; for (;;) { rc = __aes_cbc_crypt(aes_cbc, m, c, clen, flags); if (rc == 0) { break; } else { if (aes_cbc->aes_key->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_cbc->aes_key->lock); assert(rv == 0); DEBUG ("aes-cbc context at %p: re-derive protected key from %s secure key from aes key at %p", aes_cbc, i == 0 ? "current" : "old", aes_cbc->aes_key); rc = aes_key_sec2prot(aes_cbc->aes_key, i); memcpy(param->protkey, protkey->protkey, sizeof(param->protkey)); rv = pthread_mutex_unlock(&aes_cbc->aes_key->lock); assert(rv == 0); } if (rc) break; } } } ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } void zpc_aes_cbc_free(struct zpc_aes_cbc **aes_cbc) { if (aes_cbc == NULL) return; if (*aes_cbc == NULL) return; if ((*aes_cbc)->key_set) { /* Decrease aes_key's refcount. */ zpc_aes_key_free(&(*aes_cbc)->aes_key); (*aes_cbc)->key_set = 0; __aes_cbc_reset_iv(*aes_cbc); (*aes_cbc)->iv_set = 0; } __aes_cbc_reset(*aes_cbc); free(*aes_cbc); *aes_cbc = NULL; DEBUG("return"); } static void __aes_cbc_set_iv(struct zpc_aes_cbc *aes_cbc, const u8 iv[16]) { assert(aes_cbc != NULL); assert(iv != NULL); memcpy(aes_cbc->param.cv, iv, 16); } static int __aes_cbc_crypt(struct zpc_aes_cbc *aes_cbc, u8 * out, const u8 * in, size_t inlen, unsigned long flags) { struct cpacf_kmc_aes_param *param; int rc, cc; param = &aes_cbc->param; cc = cpacf_kmc(aes_cbc->fc | flags, param, out, in, inlen); assert(cc == 0 || cc == 1 || cc == 2); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto err; } rc = 0; err: return rc; } static void __aes_cbc_reset(struct zpc_aes_cbc *aes_cbc) { assert(aes_cbc != NULL); memset(&aes_cbc->param, 0, sizeof(aes_cbc->param)); __aes_cbc_reset_iv(aes_cbc); aes_cbc->iv_set = 0; if (aes_cbc->aes_key != NULL) zpc_aes_key_free(&aes_cbc->aes_key); aes_cbc->key_set = 0; aes_cbc->fc = 0; } static void __aes_cbc_reset_iv(struct zpc_aes_cbc *aes_cbc) { assert(aes_cbc != NULL); memset(aes_cbc->param.cv, 0, sizeof(aes_cbc->param.cv)); aes_cbc->iv_set = 0; } libzpc-1.3.0/src/aes_cbc_local.h000066400000000000000000000007301475140344100164720ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef AES_CBC_LOCAL_H # define AES_CBC_LOCAL_H # include "zpc/aes_key.h" # include "misc.h" # include "cpacf.h" /* * Internal aes_cbc interface. */ struct zpc_aes_cbc { struct cpacf_kmc_aes_param param; struct zpc_aes_key *aes_key; unsigned int fc; int key_set; int iv_set; }; #endif libzpc-1.3.0/src/aes_ccm.c000066400000000000000000000411251475140344100153310ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include "zpc/aes_ccm.h" #include "zpc/error.h" #include "aes_ccm_local.h" #include "aes_key_local.h" #include "cpacf.h" #include "globals.h" #include "misc.h" #include "debug.h" #include "zkey/pkey.h" #include #include #include #include #include struct aes_ccm_flags { u8 reserved:1; u8 adata:1; u8 m:3; u8 l:3; } __packed; static void __aes_ccm_set_iv(struct zpc_aes_ccm *, const u8 *, size_t); static int __aes_ccm_crypt(struct zpc_aes_ccm *, u8 *, u8 *, size_t, const u8 *, size_t, const u8 *, size_t, unsigned long); static int __aes_ccm_cbcmac(struct zpc_aes_ccm *, const u8 *, size_t); static int __aes_ccm_ctr(struct zpc_aes_ccm *, u8[16], u8 *, const u8 *, size_t); static void __aes_ccm_reset(struct zpc_aes_ccm *); static void __aes_ccm_reset_iv(struct zpc_aes_ccm *); int zpc_aes_ccm_alloc(struct zpc_aes_ccm **aes_ccm) { struct zpc_aes_ccm *new_aes_ccm = NULL; int rc; if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.aes_ccm) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_ccm == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } new_aes_ccm = calloc(1, sizeof(*new_aes_ccm)); if (new_aes_ccm == NULL) { rc = ZPC_ERROR_MALLOC; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } DEBUG("aes-ccm context at %p: allocated", new_aes_ccm); *aes_ccm = new_aes_ccm; rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_ccm_set_key(struct zpc_aes_ccm *aes_ccm, struct zpc_aes_key *aes_key) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.aes_ccm) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_ccm == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("aes-ccm context at %p: key unset", aes_ccm); __aes_ccm_reset(aes_ccm); rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); rc = aes_key_check(aes_key); if (rc) goto ret; if (aes_ccm->aes_key == aes_key) { DEBUG("aes-ccm context at %p: key at %p already set", aes_ccm, aes_key); rc = 0; /* nothing to do */ goto ret; } aes_key->refcount++; DEBUG("aes key at %p: refcount %llu", aes_key, aes_key->refcount); if (aes_ccm->key_set) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("aes-ccm context at %p: key unset", aes_ccm); __aes_ccm_reset(aes_ccm); } /* Set new key. */ assert(!aes_ccm->key_set); DEBUG("aes-ccm context at %p: key at %p set, iv unset", aes_ccm, aes_key); memcpy(aes_ccm->param_kma.protkey, aes_key->prot.protkey, sizeof(aes_ccm->param_kma.protkey)); memcpy(aes_ccm->param_kmac.protkey, aes_key->prot.protkey, sizeof(aes_ccm->param_kmac.protkey)); /* The corresponding KMAC function codes are the same as the KMA * function codes. */ aes_ccm->fc = CPACF_KMA_GCM_ENCRYPTED_AES_128 + (aes_key->keysize - 128) / 64; aes_ccm->aes_key = aes_key; aes_ccm->key_set = 1; __aes_ccm_reset_iv(aes_ccm); aes_ccm->iv_set = 0; rc = 0; ret: rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_ccm_set_iv(struct zpc_aes_ccm *aes_ccm, const u8 * iv, size_t ivlen) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_ccm) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_ccm == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if (iv == NULL) { /* Unset iv */ DEBUG("aes-ccm context at %p: iv unset", aes_ccm); __aes_ccm_reset_iv(aes_ccm); aes_ccm->iv_set = 0; rc = 0; goto ret; } /* 15 - L byte nonce. 2 <= L <= 8. */ if (ivlen < 15 - 8 || ivlen > 15 - 2) { rc = ZPC_ERROR_IVSIZE; goto ret; } if (aes_ccm->key_set != 1) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } __aes_ccm_set_iv(aes_ccm, iv, ivlen); DEBUG("aes-ccm context at %p: iv set", aes_ccm); aes_ccm->iv_set = 1; rc = 0; ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_ccm_encrypt(struct zpc_aes_ccm *aes_ccm, u8 * c, u8 * tag, size_t taglen, const u8 * aad, size_t aadlen, const u8 * m, size_t mlen) { struct cpacf_kma_gcm_aes_param *param_kma; struct cpacf_kmac_aes_param *param_kmac; struct pkey_protkey *protkey; unsigned long flags = 0; int rc, rv, i; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_ccm) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_ccm == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if ((mlen > 0 || m != NULL) && c == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } /* Valid tag byte-lengths: 16, 14, 12, 10, 8, 6, 4. */ if (taglen > 0 && tag == NULL) { rc = ZPC_ERROR_ARG3NULL; goto ret; } if (taglen % 2 != 0 || taglen > 16 || taglen < 4) { rc = ZPC_ERROR_TAGSIZE; goto ret; } /* 0 <= aad byte-length <= 2^64 - 1 */ if (aadlen > 0 && aad == NULL) { rc = ZPC_ERROR_ARG5NULL; goto ret; } if (!aes_ccm->key_set) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } if (!aes_ccm->iv_set) { rc = ZPC_ERROR_IVNOTSET; goto ret; } /* 0 <= m byte-length <= 2^(8L) - 1 */ if ((mlen > 0 || c != NULL) && m == NULL) { rc = ZPC_ERROR_ARG7NULL; goto ret; } if (aes_ccm->ivlen > 7 && (u64) mlen > (1ULL << (8 * (15 - aes_ccm->ivlen))) - 1) { rc = ZPC_ERROR_MLEN; goto ret; } rc = -1; for (i = 0; i < 2 && rc != 0; i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_ccm->aes_key->prot; param_kma = &aes_ccm->param_kma; param_kmac = &aes_ccm->param_kmac; for (;;) { rc = __aes_ccm_crypt(aes_ccm, c, tag, taglen, aad, aadlen, m, mlen, flags); if (rc == 0) { break; } else { if (aes_ccm->aes_key->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_ccm->aes_key->lock); assert(rv == 0); DEBUG ("aes-ccm context at %p: re-derive protected key from %s secure key from aes key at %p", aes_ccm, i == 0 ? "current" : "old", aes_ccm->aes_key); rc = aes_key_sec2prot(aes_ccm->aes_key, i); memcpy(param_kma->protkey, protkey->protkey, sizeof(param_kma->protkey)); memcpy(param_kmac->protkey, protkey->protkey, sizeof(param_kmac->protkey)); rv = pthread_mutex_unlock(&aes_ccm-> aes_key->lock); assert(rv == 0); } if (rc) break; } } } ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_ccm_decrypt(struct zpc_aes_ccm *aes_ccm, u8 * m, const u8 * tag, size_t taglen, const u8 * aad, size_t aadlen, const u8 * c, size_t clen) { struct cpacf_kma_gcm_aes_param *param_kma; struct cpacf_kmac_aes_param *param_kmac; struct pkey_protkey *protkey; unsigned long flags = CPACF_M; int rc, rv, i; u8 tmp[16]; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_ccm) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_ccm == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if ((clen > 0 || c != NULL) && m == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } /* Valid tag byte-lengths: 16, 14, 12, 10, 8, 6, 4. */ if (taglen > 0 && tag == NULL) { rc = ZPC_ERROR_ARG3NULL; goto ret; } if (taglen % 2 != 0 || taglen > 16 || taglen < 4) { rc = ZPC_ERROR_TAGSIZE; goto ret; } /* 0 <= aad byte-length <= 2^64 - 1 */ if (aadlen > 0 && aad == NULL) { rc = ZPC_ERROR_ARG5NULL; goto ret; } if (!aes_ccm->key_set) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } if (!aes_ccm->iv_set) { rc = ZPC_ERROR_IVNOTSET; goto ret; } /* 0 <= c byte-length <= 2^(8L) - 1 */ if ((clen > 0 || m != NULL) && c == NULL) { rc = ZPC_ERROR_ARG7NULL; goto ret; } if (aes_ccm->ivlen > 7 && (u64) clen > (1ULL << (8 * (15 - aes_ccm->ivlen))) - 1) { rc = ZPC_ERROR_CLEN; goto ret; } rc = -1; for (i = 0; i < 2 && rc != 0 && (rc != ZPC_ERROR_TAGMISMATCH); i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_ccm->aes_key->prot; param_kma = &aes_ccm->param_kma; param_kmac = &aes_ccm->param_kmac; for (;;) { memcpy(tmp, tag, taglen); rc = __aes_ccm_crypt(aes_ccm, m, tmp, taglen, aad, aadlen, c, clen, flags); if (rc == 0 || rc == ZPC_ERROR_TAGMISMATCH) { break; } else { if (aes_ccm->aes_key->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_ccm->aes_key->lock); assert(rv == 0); DEBUG ("aes-ccm context at %p: re-derive protected key from %s secure key from aes key at %p", aes_ccm, i == 0 ? "current" : "old", aes_ccm->aes_key); rc = aes_key_sec2prot(aes_ccm->aes_key, i); memcpy(param_kma->protkey, protkey->protkey, sizeof(param_kma->protkey)); memcpy(param_kmac->protkey, protkey->protkey, sizeof(param_kmac->protkey)); rv = pthread_mutex_unlock(&aes_ccm->aes_key->lock); assert(rv == 0); } if (rc) break; } } } ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } void zpc_aes_ccm_free(struct zpc_aes_ccm **aes_ccm) { if (aes_ccm == NULL) return; if (*aes_ccm == NULL) return; if ((*aes_ccm)->key_set) { /* Decrease aes_key's refcount. */ zpc_aes_key_free(&(*aes_ccm)->aes_key); (*aes_ccm)->key_set = 0; __aes_ccm_reset_iv(*aes_ccm); (*aes_ccm)->iv_set = 0; } __aes_ccm_reset(*aes_ccm); free(*aes_ccm); *aes_ccm = NULL; DEBUG("return"); } static void __aes_ccm_set_iv(struct zpc_aes_ccm *aes_ccm, const u8 * iv, size_t ivlen) { assert(aes_ccm != NULL); assert(iv != NULL); memset(aes_ccm->param_kma.reserved, 0, sizeof(aes_ccm->param_kma.reserved)); memset(aes_ccm->param_kma.t, 0, sizeof(aes_ccm->param_kma.t)); memset(aes_ccm->param_kma.h, 0, sizeof(aes_ccm->param_kma.h)); memset(aes_ccm->param_kma.j0, 0, sizeof(aes_ccm->param_kma.j0)); aes_ccm->param_kma.cv = 0; aes_ccm->param_kma.taadl = 0; aes_ccm->param_kma.tpcl = 0; memset(aes_ccm->param_kmac.icv, 0, sizeof(aes_ccm->param_kmac.icv)); memset(aes_ccm->iv, 0, sizeof(aes_ccm->iv)); aes_ccm->ivlen = ivlen; memcpy(aes_ccm->iv, iv, ivlen); } static int __aes_ccm_crypt(struct zpc_aes_ccm *aes_ccm, u8 * out, u8 * tag, size_t taglen, const u8 * aad, size_t aadlen, const u8 * in, size_t inlen, unsigned long flags) { struct aes_ccm_flags b0flags; u8 b01[32], tmp[16]; int rc, cc; size_t rem, i; assert(aes_ccm != NULL); assert(aes_ccm->key_set == 1); assert(aes_ccm->iv_set == 1); memset(&b0flags, 0, sizeof(b0flags)); memset(b01, 0, sizeof(b01)); if (aadlen) b0flags.adata = 1; b0flags.m = taglen / 2 - 1; assert(b0flags.m != 0); b0flags.l = (15 - aes_ccm->ivlen) - 1; assert(b0flags.l != 0); memcpy(b01, &b0flags, 1); memcpy(b01 + 1, aes_ccm->iv, aes_ccm->ivlen); for (i = 0; i < 16 - 1 - aes_ccm->ivlen; i++) b01[15 - i] = ((u8 *) & inlen)[sizeof(inlen) - 1 - i]; if (b0flags.adata == 1) { if (aadlen < (1ULL << 16) - (1ULL << 8)) { *(u16 *) (&(b01[16])) = aadlen; i = 16 + 2; } else if (aadlen <= 1ULL << 32) { *(u16 *) (&(b01[16])) = 0xfffe; *(u32 *) (&(b01[16])) = aadlen; i = 16 + 6; } else { *(u16 *) (&(b01[16])) = 0xffff; *(u64 *) (&(b01[16])) = aadlen; i = 16 + 10; } while (i < 32 && aadlen) { b01[i] = *aad; aad++; aadlen--; i++; } while (i < 32) { b01[i] = 0; i++; } } memset(aes_ccm->param_kmac.icv, 0, sizeof(aes_ccm->param_kmac.icv)); cc = cpacf_kmac(aes_ccm->fc, &aes_ccm->param_kmac, b01, b0flags.adata == 1 ? 32 : 16); /* Either incomplete processing or WKaVP mismatch. */ assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } rem = aadlen & 0xf; aadlen &= ~(size_t)0xf; if (aadlen) { cc = cpacf_kmac(aes_ccm->fc, &aes_ccm->param_kmac, aad, aadlen); /* Either incomplete processing or WKaVP mismatch. */ assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } aad += aadlen; } if (rem) { for (i = 0; i < rem; i++) tmp[i] = aad[i]; for (; i < 16; i++) tmp[i] = 0; cc = cpacf_kmac(aes_ccm->fc, &aes_ccm->param_kmac, tmp, 16); /* Either incomplete processing or WKaVP mismatch. */ assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } } memset(tmp, 0, 16); if (!(flags & CPACF_M)) { /* mac-then-encrypt */ rc = __aes_ccm_cbcmac(aes_ccm, in, inlen); if (rc) goto ret; rc = __aes_ccm_ctr(aes_ccm, tmp, out, in, inlen); if (rc) goto ret; for (i = 0; i < 16; i++) tmp[i] ^= aes_ccm->param_kmac.icv[i]; memcpy(tag, tmp, taglen); } else { /* decrypt-then-mac */ rc = __aes_ccm_ctr(aes_ccm, tmp, out, in, inlen); if (rc) goto ret; rc = __aes_ccm_cbcmac(aes_ccm, out, inlen); if (rc) goto ret; for (i = 0; i < taglen; i++) tmp[i] ^= tag[i]; rc = memcmp_consttime(tmp, aes_ccm->param_kmac.icv, taglen); if (rc) { rc = ZPC_ERROR_TAGMISMATCH; goto ret; } } rc = 0; ret: if (rc == ZPC_ERROR_TAGMISMATCH) { memset(out, 0, inlen); } return rc; } static int __aes_ccm_cbcmac(struct zpc_aes_ccm *aes_ccm, const u8 * in, size_t inlen) { struct aes_ccm_flags aflags; u8 a[16], tmp[16]; int rc, cc; size_t rem, i; memset(&aflags, 0, sizeof(aflags)); memset(a, 0, sizeof(a)); rem = inlen & 0xf; inlen &= ~(size_t)0xf; if (inlen) { cc = cpacf_kmac(aes_ccm->fc, &aes_ccm->param_kmac, in, inlen); /* Either incomplete processing or WKaVP mismatch. */ assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } } if (rem) { for (i = 0; i < rem; i++) tmp[i] = in[inlen + i]; for (; i < 16; i++) tmp[i] = 0; cc = cpacf_kmac(aes_ccm->fc, &aes_ccm->param_kmac, tmp, 16); /* Either incomplete processing or WKaVP mismatch. */ assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } } rc = 0; ret: return rc; } static int __aes_ccm_ctr(struct zpc_aes_ccm *aes_ccm, u8 tagkey[16], u8 * out, const u8 * in, size_t inlen) { struct aes_ccm_flags aflags; unsigned int flags; u8 a[16]; int rc, cc; u32 ctr; flags = CPACF_KMA_LAAD | CPACF_KMA_HS; memset(&aflags, 0, sizeof(aflags)); memset(a, 0, sizeof(a)); aflags.l = (15 - aes_ccm->ivlen) - 1; assert(aflags.l != 0); memcpy(a, &aflags, 1); memcpy(a + 1, aes_ccm->iv, aes_ccm->ivlen); memcpy(&ctr, a + 16 - 4, 4); ctr--; /* KMA pre-inc */ memcpy(a + 16 - 4, &ctr, 4); memset(aes_ccm->param_kma.reserved, 0, sizeof(aes_ccm->param_kma.reserved)); aes_ccm->param_kma.cv = ctr; memcpy(aes_ccm->param_kma.j0, a, 16); memset(tagkey, 0, 16); cc = cpacf_kma(aes_ccm->fc | flags, &aes_ccm->param_kma, tagkey, NULL, 0, tagkey, 16); /* Either incomplete processing or WKaVP mismatch. */ assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } cc = cpacf_kma(aes_ccm->fc | flags | CPACF_KMA_LPC, &aes_ccm->param_kma, out, NULL, 0, in, inlen); /* Either incomplete processing or WKaVP mismatch. */ assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } rc = 0; ret: return rc; } static void __aes_ccm_reset(struct zpc_aes_ccm *aes_ccm) { assert(aes_ccm != NULL); memset(&aes_ccm->param_kma, 0, sizeof(aes_ccm->param_kma)); memset(&aes_ccm->param_kmac, 0, sizeof(aes_ccm->param_kmac)); __aes_ccm_reset_iv(aes_ccm); aes_ccm->iv_set = 0; if (aes_ccm->aes_key != NULL) zpc_aes_key_free(&aes_ccm->aes_key); aes_ccm->key_set = 0; aes_ccm->fc = 0; } static void __aes_ccm_reset_iv(struct zpc_aes_ccm *aes_ccm) { assert(aes_ccm != NULL); memset(aes_ccm->param_kma.reserved, 0, sizeof(aes_ccm->param_kma.reserved)); memset(aes_ccm->param_kma.t, 0, sizeof(aes_ccm->param_kma.t)); memset(aes_ccm->param_kma.h, 0, sizeof(aes_ccm->param_kma.h)); memset(aes_ccm->param_kma.j0, 0, sizeof(aes_ccm->param_kma.j0)); aes_ccm->param_kma.cv = 0; aes_ccm->param_kma.taadl = 0; aes_ccm->param_kma.tpcl = 0; memset(aes_ccm->param_kmac.icv, 0, sizeof(aes_ccm->param_kmac.icv)); memset(aes_ccm->iv, 0, sizeof(aes_ccm->iv)); aes_ccm->ivlen = 0; aes_ccm->iv_set = 0; } libzpc-1.3.0/src/aes_ccm_local.h000066400000000000000000000010451475140344100165050ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef AES_CCM_LOCAL_H # define AES_CCM_LOCAL_H # include "zpc/aes_key.h" # include "misc.h" # include "cpacf.h" /* * Internal aes_ccm interface. */ struct zpc_aes_ccm { struct cpacf_kma_gcm_aes_param param_kma; struct cpacf_kmac_aes_param param_kmac; struct zpc_aes_key *aes_key; unsigned int fc; u8 iv[16]; size_t ivlen; int key_set; int iv_set; }; #endif libzpc-1.3.0/src/aes_cmac.c000066400000000000000000000235301475140344100154720ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include "zpc/aes_cmac.h" #include "zpc/error.h" #include "aes_cmac_local.h" #include "aes_key_local.h" #include "cpacf.h" #include "globals.h" #include "misc.h" #include "debug.h" #include "zkey/pkey.h" #include #include #include #include #include static int __aes_cmac_crypt(struct zpc_aes_cmac *, u8 *, size_t, const u8 *, size_t, unsigned long); static void __aes_cmac_reset(struct zpc_aes_cmac *); static void __aes_cmac_reset_state(struct zpc_aes_cmac *); int zpc_aes_cmac_alloc(struct zpc_aes_cmac **aes_cmac) { struct zpc_aes_cmac *new_aes_cmac = NULL; int rc; if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.aes_cmac) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_cmac == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } new_aes_cmac = calloc(1, sizeof(*new_aes_cmac)); if (new_aes_cmac == NULL) { rc = ZPC_ERROR_MALLOC; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } DEBUG("aes-cmac context at %p: allocated", new_aes_cmac); *aes_cmac = new_aes_cmac; rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_cmac_set_key(struct zpc_aes_cmac *aes_cmac, struct zpc_aes_key *aes_key) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.aes_cmac) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_cmac == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("aes-cmac context at %p: key unset", aes_cmac); __aes_cmac_reset(aes_cmac); rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); rc = aes_key_check(aes_key); if (rc) goto ret; if (aes_cmac->aes_key == aes_key) { __aes_cmac_reset_state(aes_cmac); DEBUG("aes-cmac context at %p: key at %p already set", aes_cmac, aes_key); rc = 0; goto ret; } aes_key->refcount++; DEBUG("aes key at %p: refcount %llu", aes_key, aes_key->refcount); if (aes_cmac->key_set) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("aes-cmac context at %p: key unset", aes_cmac); __aes_cmac_reset(aes_cmac); } /* Set new key. */ assert(!aes_cmac->key_set); DEBUG("aes-cmac context at %p: key at %p set, iv unset", aes_cmac, aes_key); memset(&aes_cmac->param_kmac, 0, sizeof(aes_cmac->param_kmac)); memset(&aes_cmac->param_pcc, 0, sizeof(aes_cmac->param_pcc)); memcpy(aes_cmac->param_kmac.protkey, aes_key->prot.protkey, sizeof(aes_cmac->param_kmac.protkey)); memcpy(aes_cmac->param_pcc.protkey, aes_key->prot.protkey, sizeof(aes_cmac->param_pcc.protkey)); aes_cmac->fc = CPACF_KMAC_ENCRYPTED_AES_128 + (aes_key->keysize - 128) / 64; aes_cmac->aes_key = aes_key; aes_cmac->key_set = 1; rc = 0; ret: rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_cmac_sign(struct zpc_aes_cmac *aes_cmac, u8 * tag, size_t taglen, const u8 * m, size_t mlen) { struct cpacf_kmac_aes_param *param_kmac; struct cpacf_pcc_cmac_aes_param *param_pcc; struct pkey_protkey *protkey; unsigned long flags = 0; int rc, rv, i; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_cmac) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_cmac == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } /* Valid tag byte-lengths: >= 8, <= 16. */ if (taglen > 0 && tag == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } if (tag != NULL && (taglen > 16 || taglen < 8)) { rc = ZPC_ERROR_TAGSIZE; goto ret; } if (mlen > 0 && mlen % 16 != 0 && tag == NULL) { rc = ZPC_ERROR_ARG5RANGE; goto ret; } if (!aes_cmac->key_set) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } rc = -1; for (i = 0; i < 2 && rc != 0; i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_cmac->aes_key->prot; param_kmac = &aes_cmac->param_kmac; param_pcc = &aes_cmac->param_pcc; for (;;) { rc = __aes_cmac_crypt(aes_cmac, tag, taglen, m, mlen, flags); if (rc == 0) { break; } else { if (aes_cmac->aes_key->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_cmac->aes_key->lock); assert(rv == 0); DEBUG ("aes-cmac context at %p: re-derive protected key from %s secure key from aes key at %p", aes_cmac, i == 0 ? "current" : "old", aes_cmac->aes_key); rc = aes_key_sec2prot(aes_cmac->aes_key, i); memcpy(param_kmac->protkey, protkey->protkey, sizeof(param_kmac->protkey)); memcpy(param_pcc->protkey, protkey->protkey, sizeof(param_pcc->protkey)); rv = pthread_mutex_unlock(&aes_cmac->aes_key->lock); assert(rv == 0); } if (rc) break; } } } ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_cmac_verify(struct zpc_aes_cmac *aes_cmac, const u8 * tag, size_t taglen, const u8 * m, size_t mlen) { struct cpacf_kmac_aes_param *param_kmac; struct cpacf_pcc_cmac_aes_param *param_pcc; struct pkey_protkey *protkey; unsigned long flags = 0; int rc, rv, i; u8 tmp[16]; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_cmac) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_cmac == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } /* Valid tag byte-lengths: >= 8, <= 16. */ if (taglen > 0 && tag == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } if (tag != NULL && (taglen > 16 || taglen < 8)) { rc = ZPC_ERROR_TAGSIZE; goto ret; } if (mlen > 0 && mlen % 16 != 0 && tag == NULL) { rc = ZPC_ERROR_ARG5RANGE; goto ret; } if (!aes_cmac->key_set) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } rc = -1; for (i = 0; i < 2 && (rc != 0 && rc != ZPC_ERROR_TAGMISMATCH); i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_cmac->aes_key->prot; param_kmac = &aes_cmac->param_kmac; param_pcc = &aes_cmac->param_pcc; for (;;) { rc = __aes_cmac_crypt(aes_cmac, tag == NULL ? NULL : tmp, tag == NULL ? 0 : sizeof(tmp), m, mlen, flags); if (rc == 0) { if (tag != NULL) { rc = memcmp_consttime(tmp, tag, taglen); if (rc != 0) rc = ZPC_ERROR_TAGMISMATCH; } break; } else { if (aes_cmac->aes_key->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_cmac->aes_key->lock); assert(rv == 0); DEBUG ("aes-cmac context at %p: re-derive protected key from %s secure key from aes key at %p", aes_cmac, i == 0 ? "current" : "old", aes_cmac->aes_key); rc = aes_key_sec2prot(aes_cmac->aes_key, i); memcpy(param_kmac->protkey, protkey->protkey, sizeof(param_kmac->protkey)); memcpy(param_pcc->protkey, protkey->protkey, sizeof(param_pcc->protkey)); rv = pthread_mutex_unlock(&aes_cmac->aes_key->lock); assert(rv == 0); } if (rc) break; } } } ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } void zpc_aes_cmac_free(struct zpc_aes_cmac **aes_cmac) { if (aes_cmac == NULL) return; if (*aes_cmac == NULL) return; if ((*aes_cmac)->key_set) { /* Decrease aes_key's refcount. */ zpc_aes_key_free(&(*aes_cmac)->aes_key); (*aes_cmac)->key_set = 0; } __aes_cmac_reset(*aes_cmac); free(*aes_cmac); *aes_cmac = NULL; DEBUG("return"); } static int __aes_cmac_crypt(struct zpc_aes_cmac *aes_cmac, u8 * tag, size_t taglen, const u8 * in, size_t inlen, unsigned long flags) { size_t rem; int rc, cc; assert(aes_cmac != NULL); assert((tag != NULL) || (tag == NULL && inlen % 16 == 0)); assert((tag == NULL) || (8 <= taglen && taglen <= 16)); rem = inlen & 0xf; inlen &= ~(size_t)0xf; if (tag != NULL && rem == 0 && inlen >= 16) { inlen -= 16; rem += 16; } if (inlen) { cc = cpacf_kmac(aes_cmac->fc | flags, &aes_cmac->param_kmac, in, inlen); assert(cc == 0 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto err; } in += inlen; } if (tag != NULL) { aes_cmac->param_pcc.ml = rem * 8; memset(aes_cmac->param_pcc.message, 0, sizeof(aes_cmac->param_pcc.message)); memcpy(aes_cmac->param_pcc.message, in, rem); memcpy(aes_cmac->param_pcc.icv, aes_cmac->param_kmac.icv, sizeof(aes_cmac->param_pcc.icv)); cc = cpacf_pcc(aes_cmac->fc | flags, &aes_cmac->param_pcc); assert(cc == 0 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto err; } memcpy(tag, aes_cmac->param_pcc.icv, taglen); __aes_cmac_reset_state(aes_cmac); } rc = 0; err: return rc; } static void __aes_cmac_reset(struct zpc_aes_cmac *aes_cmac) { assert(aes_cmac != NULL); __aes_cmac_reset_state(aes_cmac); memset(&aes_cmac->param_kmac, 0, sizeof(aes_cmac->param_kmac)); memset(&aes_cmac->param_pcc, 0, sizeof(aes_cmac->param_pcc)); if (aes_cmac->aes_key != NULL) zpc_aes_key_free(&aes_cmac->aes_key); aes_cmac->key_set = 0; aes_cmac->fc = 0; } static void __aes_cmac_reset_state(struct zpc_aes_cmac *aes_cmac) { assert(aes_cmac != NULL); memset(aes_cmac->param_kmac.icv, 0, sizeof(aes_cmac->param_kmac.icv)); memset(&aes_cmac->param_pcc.icv, 0, sizeof(aes_cmac->param_pcc.icv)); memset(&aes_cmac->param_pcc.message, 0, sizeof(aes_cmac->param_pcc.message)); aes_cmac->param_pcc.ml = 0; } libzpc-1.3.0/src/aes_cmac_local.h000066400000000000000000000010011475140344100166360ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef AES_CMAC_LOCAL_H # define AES_CMAC_LOCAL_H # include "zpc/aes_key.h" # include "misc.h" # include "cpacf.h" /* * Internal aes_cmac interface. */ struct zpc_aes_cmac { struct cpacf_kmac_aes_param param_kmac; struct cpacf_pcc_cmac_aes_param param_pcc; struct zpc_aes_key *aes_key; unsigned int fc; int key_set; }; #endif libzpc-1.3.0/src/aes_ecb.c000066400000000000000000000166371475140344100153320ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include "zpc/aes_ecb.h" #include "zpc/error.h" #include "aes_ecb_local.h" #include "aes_key_local.h" #include "cpacf.h" #include "globals.h" #include "misc.h" #include "debug.h" #include "zkey/pkey.h" #include #include #include #include #include static int __aes_ecb_crypt(struct zpc_aes_ecb *, u8 *, const u8 *, size_t, unsigned long); static void __aes_ecb_reset(struct zpc_aes_ecb *); int zpc_aes_ecb_alloc(struct zpc_aes_ecb **aes_ecb) { struct zpc_aes_ecb *new_aes_ecb = NULL; int rc; if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.aes_ecb) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_ecb == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } new_aes_ecb = calloc(1, sizeof(*new_aes_ecb)); if (new_aes_ecb == NULL) { rc = ZPC_ERROR_MALLOC; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } DEBUG("aes-ecb context at %p: allocated", new_aes_ecb); *aes_ecb = new_aes_ecb; rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_ecb_set_key(struct zpc_aes_ecb *aes_ecb, struct zpc_aes_key *aes_key) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.aes_ecb) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_ecb == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("aes-ecb context at %p: key unset", aes_ecb); __aes_ecb_reset(aes_ecb); rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); rc = aes_key_check(aes_key); if (rc) goto ret; if (aes_ecb->aes_key == aes_key) { DEBUG("aes-ecb context at %p: key at %p already set", aes_ecb, aes_key); rc = 0; /* nothing to do */ goto ret; } aes_key->refcount++; DEBUG("aes key at %p: refcount %llu", aes_key, aes_key->refcount); if (aes_ecb->key_set) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("aes-ecb context at %p: key unset", aes_ecb); __aes_ecb_reset(aes_ecb); } /* Set new key. */ assert(!aes_ecb->key_set); DEBUG("aes-ecb context at %p: key at %p set", aes_ecb, aes_key); memcpy(aes_ecb->param.protkey, aes_key->prot.protkey, sizeof(aes_ecb->param.protkey)); aes_ecb->fc = CPACF_KM_ENCRYPTED_AES_128 + (aes_key->keysize - 128) / 64; aes_ecb->aes_key = aes_key; aes_ecb->key_set = 1; rc = 0; ret: rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_ecb_encrypt(struct zpc_aes_ecb *aes_ecb, u8 * c, const u8 * m, size_t mlen) { struct cpacf_km_aes_param *param; struct pkey_protkey *protkey; unsigned long flags = 0; int rc, rv, i; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_ecb) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_ecb == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if ((mlen > 0 || m != NULL) && c == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } if ((mlen > 0 || c != NULL) && m == NULL) { rc = ZPC_ERROR_ARG3NULL; goto ret; } if (mlen % 16 != 0) { rc = ZPC_ERROR_MLEN; goto ret; } if (!aes_ecb->key_set) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } rc = -1; for (i = 0; i < 2 && rc != 0; i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_ecb->aes_key->prot; param = &aes_ecb->param; for (;;) { rc = __aes_ecb_crypt(aes_ecb, c, m, mlen, flags); if (rc == 0) { break; } else { if (aes_ecb->aes_key->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_ecb->aes_key->lock); assert(rv == 0); DEBUG ("aes-ecb context at %p: re-derive protected key from %s secure key from aes key at %p", aes_ecb, i == 0 ? "current" : "old", aes_ecb->aes_key); rc = aes_key_sec2prot(aes_ecb->aes_key, i); memcpy(param->protkey, protkey->protkey, sizeof(param->protkey)); rv = pthread_mutex_unlock(&aes_ecb->aes_key->lock); assert(rv == 0); } if (rc) break; } } } ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_ecb_decrypt(struct zpc_aes_ecb *aes_ecb, u8 * m, const u8 * c, size_t clen) { struct cpacf_km_aes_param *param; struct pkey_protkey *protkey; unsigned long flags = CPACF_M; /* decrypt */ int rc, rv, i; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_ecb) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_ecb == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if ((clen > 0 || c != NULL) && m == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } if ((clen > 0 || m != NULL) && c == NULL) { rc = ZPC_ERROR_ARG3NULL; goto ret; } if (clen % 16 != 0) { rc = ZPC_ERROR_CLEN; goto ret; } if (!aes_ecb->key_set) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } rc = -1; for (i = 0; i < 2 && rc != 0; i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_ecb->aes_key->prot; param = &aes_ecb->param; for (;;) { rc = __aes_ecb_crypt(aes_ecb, m, c, clen, flags); if (rc == 0) { break; } else { if (aes_ecb->aes_key->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_ecb->aes_key->lock); assert(rv == 0); DEBUG ("aes-ecb context at %p: re-derive protected key from %s secure key from aes key at %p", aes_ecb, i == 0 ? "current" : "old", aes_ecb->aes_key); rc = aes_key_sec2prot(aes_ecb->aes_key, i); memcpy(param->protkey, protkey->protkey, sizeof(param->protkey)); rv = pthread_mutex_unlock(&aes_ecb->aes_key->lock); assert(rv == 0); } if (rc) break; } } } ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } void zpc_aes_ecb_free(struct zpc_aes_ecb **aes_ecb) { if (aes_ecb == NULL) return; if (*aes_ecb == NULL) return; if ((*aes_ecb)->key_set) { /* Decrease aes_key's refcount. */ zpc_aes_key_free(&(*aes_ecb)->aes_key); (*aes_ecb)->key_set = 0; } __aes_ecb_reset(*aes_ecb); free(*aes_ecb); *aes_ecb = NULL; DEBUG("return"); } static int __aes_ecb_crypt(struct zpc_aes_ecb *aes_ecb, u8 * out, const u8 * in, size_t inlen, unsigned long flags) { struct cpacf_km_aes_param *param; int rc, cc; param = &aes_ecb->param; cc = cpacf_km(aes_ecb->fc | flags, param, out, in, inlen); assert(cc == 0 || cc == 1 || cc == 2); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto err; } rc = 0; err: return rc; } static void __aes_ecb_reset(struct zpc_aes_ecb *aes_ecb) { assert(aes_ecb != NULL); memset(&aes_ecb->param, 0, sizeof(aes_ecb->param)); if (aes_ecb->aes_key != NULL) zpc_aes_key_free(&aes_ecb->aes_key); aes_ecb->key_set = 0; aes_ecb->fc = 0; } libzpc-1.3.0/src/aes_ecb_local.h000066400000000000000000000007121475140344100164740ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef AES_ECB_LOCAL_H # define AES_ECB_LOCAL_H # include "zpc/aes_key.h" # include "misc.h" # include "cpacf.h" /* * Internal aes_ecb interface. */ struct zpc_aes_ecb { struct cpacf_km_aes_param param; struct zpc_aes_key *aes_key; unsigned int fc; int key_set; }; #endif libzpc-1.3.0/src/aes_gcm.c000066400000000000000000000360651475140344100153440ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include "zpc/aes_gcm.h" #include "zpc/error.h" #include "aes_gcm_local.h" #include "aes_key_local.h" #include "cpacf.h" #include "globals.h" #include "misc.h" #include "debug.h" #include "zkey/pkey.h" #include #include #include #include #include static int __aes_gcm_set_iv(struct zpc_aes_gcm *, const u8 *, size_t); static int __aes_gcm_crypt(struct zpc_aes_gcm *, u8 *, u8 *, size_t, const u8 *, size_t, const u8 *, size_t, unsigned long); static void __aes_gcm_reset(struct zpc_aes_gcm *); static void __aes_gcm_reset_iv(struct zpc_aes_gcm *); int zpc_aes_gcm_alloc(struct zpc_aes_gcm **aes_gcm) { struct zpc_aes_gcm *new_aes_gcm = NULL; int rc; if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.aes_gcm) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_gcm == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } new_aes_gcm = calloc(1, sizeof(*new_aes_gcm)); if (new_aes_gcm == NULL) { rc = ZPC_ERROR_MALLOC; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } DEBUG("aes-gcm context at %p: allocated", new_aes_gcm); *aes_gcm = new_aes_gcm; rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_gcm_set_key(struct zpc_aes_gcm *aes_gcm, struct zpc_aes_key *aes_key) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.aes_gcm) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_gcm == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("aes-gcm context at %p: key unset", aes_gcm); __aes_gcm_reset(aes_gcm); rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); rc = aes_key_check(aes_key); if (rc) goto ret; if (aes_gcm->aes_key == aes_key) { DEBUG("aes-gcm context at %p: key at %p already set", aes_gcm, aes_key); rc = 0; /* nothing to do */ goto ret; } aes_key->refcount++; DEBUG("aes key at %p: refcount %llu", aes_key, aes_key->refcount); if (aes_gcm->key_set) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("aes-gcm context at %p: key unset", aes_gcm); __aes_gcm_reset(aes_gcm); } /* Set new key. */ assert(!aes_gcm->key_set); DEBUG("aes-gcm context at %p: key at %p set, iv unset", aes_gcm, aes_key); memcpy(aes_gcm->param.protkey, aes_key->prot.protkey, sizeof(aes_gcm->param.protkey)); aes_gcm->fc = CPACF_KMA_GCM_ENCRYPTED_AES_128 + (aes_key->keysize - 128) / 64; aes_gcm->aes_key = aes_key; aes_gcm->key_set = 1; __aes_gcm_reset_iv(aes_gcm); aes_gcm->iv_set = 0; rc = 0; ret: rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_gcm_create_iv(struct zpc_aes_gcm *aes_gcm, u8 *iv, size_t ivlen) { u8 *iv_tmp = NULL; int rc; if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_gcm) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_gcm == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if (iv == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } /* 12 <= iv bit-length <= 2^64 - 1, iv bit-length % 8 == 0 */ if (ivlen < GCM_RECOMMENDED_IV_LENGTH || ivlen > GCM_MAX_IV_LENGTH) { rc = ZPC_ERROR_IVSIZE; goto ret; } if (aes_gcm->key_set != 1) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } iv_tmp = calloc(ivlen, 1); if (!iv_tmp) { rc = ZPC_ERROR_MALLOC; goto ret; } if (local_rng(iv_tmp, ivlen) != 0) { rc = ZPC_ERROR_RNDGEN; goto ret; } aes_gcm->iv_created = 0; rc = zpc_aes_gcm_set_iv(aes_gcm, iv_tmp, ivlen); if (rc != 0) goto ret; DEBUG("aes-gcm context at %p: iv created and set", aes_gcm); aes_gcm->iv_set = 1; aes_gcm->iv_created = 1; memcpy(iv, iv_tmp, ivlen); rc = 0; ret: if (iv_tmp != NULL) free(iv_tmp); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_gcm_set_iv(struct zpc_aes_gcm *aes_gcm, const u8 * iv, size_t ivlen) { struct cpacf_kma_gcm_aes_param *param; struct pkey_protkey *protkey; int rc, rv, i; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_gcm) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_gcm == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if (iv == NULL) { /* Unset iv */ DEBUG("aes-gcm context at %p: iv unset", aes_gcm); __aes_gcm_reset_iv(aes_gcm); aes_gcm->iv_set = 0; rc = 0; goto ret; } /* 1 <= iv bit-length <= 2^64 - 1, iv bit-length % 8 == 0 */ if (ivlen < 1 || ivlen > GCM_MAX_IV_LENGTH) { rc = ZPC_ERROR_IVSIZE; goto ret; } if (aes_gcm->key_set != 1) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } if (aes_gcm->iv_created == 1) { rc = ZPC_ERROR_GCM_IV_CREATED_INTERNALLY; goto ret; } rc = -1; for (i = 0; i < 2 && rc != 0; i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_gcm->aes_key->prot; param = &aes_gcm->param; for (;;) { rc = __aes_gcm_set_iv(aes_gcm, iv, ivlen); if (rc == 0) { break; } else { if (aes_gcm->aes_key->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_gcm->aes_key->lock); assert(rv == 0); DEBUG ("aes-gcm context at %p: re-derive protected key from %s secure key from aes key at %p", aes_gcm, i == 0 ? "current" : "old", aes_gcm->aes_key); rc = aes_key_sec2prot(aes_gcm->aes_key, i); memcpy(param->protkey, protkey->protkey, sizeof(param->protkey)); rv = pthread_mutex_unlock(&aes_gcm->aes_key->lock); assert(rv == 0); } if (rc) break; } } } if (rc) goto ret; DEBUG("aes-gcm context at %p: iv set", aes_gcm); aes_gcm->iv_set = 1; ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_gcm_encrypt(struct zpc_aes_gcm *aes_gcm, u8 * c, u8 * tag, size_t taglen, const u8 * aad, size_t aadlen, const u8 * m, size_t mlen) { struct cpacf_kma_gcm_aes_param *param; struct pkey_protkey *protkey; unsigned long flags = 0; int rc, rv, i; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_gcm) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_gcm == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if ((mlen > 0 || m != NULL) && c == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } /* Valid tag bit-lengths: 128, 120, 112, 104, 96, 64, 32. */ if (taglen > 0 && tag == NULL) { rc = ZPC_ERROR_ARG3NULL; goto ret; } if (taglen > 16 || (taglen > 0 && taglen < 12 && taglen != 8 && taglen != 4)) { rc = ZPC_ERROR_TAGSIZE; goto ret; } /* aad bit-length <= 2^64 - 1, aad bit-length % 8 == 0 */ if (aadlen > 0 && aad == NULL) { rc = ZPC_ERROR_ARG5NULL; goto ret; } if (aes_gcm->param.taadl / 8 + aadlen > GCM_MAX_TOTAL_AAD_LENGTH) { rc = ZPC_ERROR_AADLEN; goto ret; } if (aadlen > 0 && aadlen % 16 != 0 && m == NULL && tag == NULL) { rc = ZPC_ERROR_ARG6RANGE; goto ret; } /* m bit-length <= 2^39 - 256, m bit-length % 8 == 0 */ if ((mlen > 0 || c != NULL) && m == NULL) { rc = ZPC_ERROR_ARG7NULL; goto ret; } if (aes_gcm->param.tpcl / 8 + mlen > GCM_MAX_TOTAL_PLAINTEXT_LENGTH) { rc = ZPC_ERROR_MLEN; goto ret; } if (mlen > 0 && mlen % 16 != 0 && tag == NULL) { rc = ZPC_ERROR_ARG8RANGE; goto ret; } if (!aes_gcm->key_set) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } if (!aes_gcm->iv_set) { rc = ZPC_ERROR_IVNOTSET; goto ret; } if ((m != NULL && c != NULL) || tag != NULL) { flags |= CPACF_KMA_LAAD; if (tag != NULL) flags |= CPACF_KMA_LPC; } aes_gcm->param.taadl += (aadlen * 8); aes_gcm->param.tpcl += (mlen * 8); rc = -1; for (i = 0; i < 2 && rc != 0; i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_gcm->aes_key->prot; param = &aes_gcm->param; for (;;) { rc = __aes_gcm_crypt(aes_gcm, c, tag, taglen, aad, aadlen, m, mlen, flags); if (rc == 0) { break; } else { if (aes_gcm->aes_key->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_gcm->aes_key->lock); assert(rv == 0); DEBUG ("aes-gcm context at %p: re-derive protected key from %s secure key from aes key at %p", aes_gcm, i == 0 ? "current" : "old", aes_gcm->aes_key); rc = aes_key_sec2prot(aes_gcm->aes_key, i); memcpy(param->protkey, protkey->protkey, sizeof(param->protkey)); rv = pthread_mutex_unlock(&aes_gcm->aes_key->lock); assert(rv == 0); } if (rc) break; } } } ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_gcm_decrypt(struct zpc_aes_gcm *aes_gcm, u8 * m, const u8 * tag, size_t taglen, const u8 * aad, size_t aadlen, const u8 * c, size_t clen) { struct cpacf_kma_gcm_aes_param *param; struct pkey_protkey *protkey; unsigned long flags = CPACF_M; /* decrypt */ int rc, rv, i; u8 tmp[16]; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_gcm) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_gcm == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if ((clen > 0 || c != NULL) && m == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } /* Valid tag bit-lengths: 128, 120, 112, 104, 96, 64, 32. */ if (taglen > 0 && tag == NULL) { rc = ZPC_ERROR_ARG3NULL; goto ret; } if (taglen > 16 || (taglen > 0 && taglen < 12 && taglen != 8 && taglen != 4)) { rc = ZPC_ERROR_TAGSIZE; goto ret; } /* aad bit-length <= 2^64 - 1, aad bit-length % 8 == 0 */ if (aadlen > 0 && aad == NULL) { rc = ZPC_ERROR_ARG5NULL; goto ret; } if (aes_gcm->param.taadl / 8 + aadlen > GCM_MAX_TOTAL_AAD_LENGTH) { rc = ZPC_ERROR_AADLEN; goto ret; } if (aadlen > 0 && aadlen % 16 != 0 && c == NULL && tag == NULL) { rc = ZPC_ERROR_ARG6RANGE; goto ret; } /* c bit-length <= 2^39 - 256, c bit-length % 8 == 0 */ if ((clen > 0 || m != NULL) && c == NULL) { rc = ZPC_ERROR_ARG7NULL; goto ret; } if (aes_gcm->param.tpcl / 8 + clen > GCM_MAX_TOTAL_PLAINTEXT_LENGTH) { rc = ZPC_ERROR_CLEN; goto ret; } if (clen > 0 && clen % 16 != 0 && tag == NULL) { rc = ZPC_ERROR_ARG8RANGE; goto ret; } if (!aes_gcm->key_set) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } if (!aes_gcm->iv_set) { rc = ZPC_ERROR_IVNOTSET; goto ret; } if (aes_gcm->iv_created) { rc = ZPC_ERROR_GCM_IV_CREATED_INTERNALLY; goto ret; } if ((m != NULL && c != NULL) || tag != NULL) { flags |= CPACF_KMA_LAAD; if (tag != NULL) flags |= CPACF_KMA_LPC; } aes_gcm->param.taadl += (aadlen * 8); aes_gcm->param.tpcl += (clen * 8); rc = -1; for (i = 0; i < 2 && (rc != 0 && rc != ZPC_ERROR_TAGMISMATCH); i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_gcm->aes_key->prot; param = &aes_gcm->param; for (;;) { rc = __aes_gcm_crypt(aes_gcm, m, tmp, sizeof(tmp), aad, aadlen, c, clen, flags); if (rc == 0) { rc = memcmp_consttime(tmp, tag, taglen); if (rc) rc = ZPC_ERROR_TAGMISMATCH; break; } else { if (aes_gcm->aes_key->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_gcm->aes_key->lock); assert(rv == 0); DEBUG ("aes-gcm context at %p: re-derive protected key from %s secure key from aes key at %p", aes_gcm, i == 0 ? "current" : "old", aes_gcm->aes_key); rc = aes_key_sec2prot(aes_gcm->aes_key, i); memcpy(param->protkey, protkey->protkey, sizeof(param->protkey)); rv = pthread_mutex_unlock(&aes_gcm->aes_key->lock); assert(rv == 0); } if (rc) break; } } } ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } void zpc_aes_gcm_free(struct zpc_aes_gcm **aes_gcm) { if (aes_gcm == NULL) return; if (*aes_gcm == NULL) return; if ((*aes_gcm)->key_set) { /* Decrease aes_key's refcount. */ zpc_aes_key_free(&(*aes_gcm)->aes_key); (*aes_gcm)->key_set = 0; __aes_gcm_reset_iv(*aes_gcm); (*aes_gcm)->iv_set = 0; } __aes_gcm_reset(*aes_gcm); free(*aes_gcm); *aes_gcm = NULL; DEBUG("return"); } static int __aes_gcm_set_iv(struct zpc_aes_gcm *aes_gcm, const u8 * iv, size_t ivlen) { struct cpacf_kma_gcm_aes_param *param; size_t ivpadlen; u64 *ivpad = NULL; int rc, cc; assert(aes_gcm != NULL); assert(iv != NULL); assert(ivlen <= SIZE_MAX - 16); param = &aes_gcm->param; memset(param->reserved, 0, sizeof(param->reserved)); memset(param->t, 0, sizeof(param->t)); param->taadl = 0; param->tpcl = 0; if (ivlen == 12) { memcpy(param->j0, iv, ivlen); param->j0[12] = 0; param->j0[13] = 0; param->j0[14] = 0; param->j0[15] = 1; param->cv = 1; } else { ivpadlen = (ivlen + 15) / 16 * 16 + 16; ivpad = calloc(1, ivpadlen); if (ivpad == NULL) return ZPC_ERROR_MALLOC; memcpy(ivpad, iv, ivlen); ivpad[ivpadlen / 8 - 1] = ivlen * 8; memset(param->j0, 0, sizeof(param->j0)); cc = cpacf_kma(aes_gcm->fc, param, NULL, (u8 *) ivpad, ivpadlen, NULL, 0); /* Either incomplete processing or WKaVP mismatch. */ assert(cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } aes_gcm->fc |= CPACF_KMA_HS; memcpy(¶m->cv, param->t + 12, sizeof(param->cv)); memcpy(param->j0, param->t, sizeof(param->j0)); memset(param->t, 0, sizeof(param->t)); } rc = 0; ret: free(ivpad); return rc; } static int __aes_gcm_crypt(struct zpc_aes_gcm *aes_gcm, u8 * out, u8 * tag, size_t taglen, const u8 * aad, size_t aadlen, const u8 * in, size_t inlen, unsigned long flags) { struct cpacf_kma_gcm_aes_param *param; int rc, cc; param = &aes_gcm->param; cc = cpacf_kma(aes_gcm->fc | flags, param, out, aad, aadlen, in, inlen); assert(cc == 0 || cc == 1 || cc == 2); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto err; } aes_gcm->fc |= CPACF_KMA_HS; memcpy(tag, param->t, taglen); rc = 0; err: return rc; } static void __aes_gcm_reset(struct zpc_aes_gcm *aes_gcm) { assert(aes_gcm != NULL); memset(&aes_gcm->param, 0, sizeof(aes_gcm->param)); __aes_gcm_reset_iv(aes_gcm); aes_gcm->iv_set = 0; if (aes_gcm->aes_key != NULL) zpc_aes_key_free(&aes_gcm->aes_key); aes_gcm->key_set = 0; aes_gcm->fc = 0; } static void __aes_gcm_reset_iv(struct zpc_aes_gcm *aes_gcm) { assert(aes_gcm != NULL); memset(aes_gcm->param.reserved, 0, sizeof(aes_gcm->param.reserved)); memset(aes_gcm->param.t, 0, sizeof(aes_gcm->param.t)); memset(aes_gcm->param.j0, 0, sizeof(aes_gcm->param.j0)); aes_gcm->param.cv = 0; aes_gcm->param.taadl = 0; aes_gcm->param.tpcl = 0; aes_gcm->fc &= ~(CPACF_KMA_LAAD | CPACF_KMA_LPC); aes_gcm->iv_set = 0; } libzpc-1.3.0/src/aes_gcm_local.h000066400000000000000000000017511475140344100165150ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef AES_GCM_LOCAL_H # define AES_GCM_LOCAL_H # include "zpc/aes_key.h" # include "misc.h" # include "cpacf.h" /* * Internal aes_gcm interface. */ #define GCM_RECOMMENDED_IV_LENGTH 12 /* * NIST SP 800-38d: 1 <= bitlen(iv) <= 2^64 - 1 * => 1 <= bytelen(iv) <= 2^61 - 1 */ #define GCM_MAX_IV_LENGTH ((2ULL << 61) - 1) /* * NIST SP 800-38d: bitlen(A) <= 2^64 - 1 * => 0 <= bytelen(A) <= 2^61 - 1 */ #define GCM_MAX_TOTAL_AAD_LENGTH ((2ULL << 61) - 1) /* * NIST SP 800-38d: bitlen(P) <= 2^39 - 256; * => 0 <= bytelen(P) <= 2^36 - 32 */ #define GCM_MAX_TOTAL_PLAINTEXT_LENGTH ((2ULL << 36) - 32) struct zpc_aes_gcm { struct cpacf_kma_gcm_aes_param param; struct zpc_aes_key *aes_key; unsigned int fc; int key_set; int iv_set; int iv_created; }; #endif libzpc-1.3.0/src/aes_key.c000066400000000000000000001041731475140344100153620ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include "zpc/aes_key.h" #include "zpc/error.h" #include "aes_key_local.h" #include "globals.h" #include "debug.h" #include "misc.h" #include "zkey/pkey.h" #include #include #include #include #include #include #include static void __aes_key_reset(struct zpc_aes_key *); static int aes_key_blob_has_valid_mkvp(struct zpc_aes_key *aes_key, const unsigned char *buf, size_t buflen); static int aes_key_blob_is_pkey_extractable(struct zpc_aes_key *aes_key, const unsigned char *buf, size_t buflen); static int aes_key_add_ep11_header(struct zpc_aes_key *aes_key); static int aes_key_blob_has_a_session(struct zpc_aes_key *aes_key); int aes_key_pvsec2prot(struct zpc_aes_key *aes_key); int aes_key_blob_is_valid_pvsecret_id(struct zpc_aes_key *aes_key, const unsigned char *id); int zpc_aes_key_alloc(struct zpc_aes_key **aes_key) { pthread_mutexattr_t attr; struct zpc_aes_key *new_aes_key = NULL; int rc, rv, attr_init = 0; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (aes_key == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } new_aes_key = calloc(1, sizeof(*new_aes_key)); if (new_aes_key == NULL) { rc = ZPC_ERROR_MALLOC; goto ret; } rc = pthread_mutexattr_init(&attr); if (rc) { rc = ZPC_ERROR_MALLOC; goto ret; } attr_init = 1; rv = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); assert(rv == 0); rc = pthread_mutex_init(&new_aes_key->lock, &attr); if (rc) { rc = ZPC_ERROR_INITLOCK; goto ret; } new_aes_key->refcount = 1; DEBUG("aes key at %p: refcount %llu", new_aes_key, new_aes_key->refcount); *aes_key = new_aes_key; rc = 0; ret: if (attr_init == 1) { rv = pthread_mutexattr_destroy(&attr); assert(rv == 0); } if (rc) free(new_aes_key); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_key_set_size(struct zpc_aes_key *aes_key, int keysize) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } switch (keysize) { case 128: /* fall-through */ case 192: /* fall-through */ case 256: break; default: rc = ZPC_ERROR_KEYSIZE; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); if (aes_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } if (aes_key->key_set == 1 && aes_key->keysize != keysize) { /* Unset key if it does not match the new keysize. */ DEBUG("aes key at %p: key unset", aes_key); memset(&aes_key->cur, 0, sizeof(aes_key->cur)); memset(&aes_key->old, 0, sizeof(aes_key->old)); aes_key->key_set = 0; } DEBUG("aes key at %p: size set to %d", aes_key, keysize); aes_key->keysize = keysize; aes_key->keysize_set = 1; rc = 0; ret: rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_key_set_type(struct zpc_aes_key *aes_key, int type) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } switch (type) { case ZPC_AES_KEY_TYPE_CCA_DATA: /* fall-through */ case ZPC_AES_KEY_TYPE_CCA_CIPHER: /* fall-through */ case ZPC_AES_KEY_TYPE_EP11: break; case ZPC_AES_KEY_TYPE_PVSECRET: if (!swcaps.uv_pvsecrets) { rc = ZPC_ERROR_UV_PVSECRETS_NOT_AVAILABLE; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } break; default: rc = ZPC_ERROR_KEYTYPE; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); if (aes_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } if (aes_key->type_set == 1 && aes_key->type != type && aes_key->mkvp_set == 1) { /* Update mkvp-based apqn choices in case of type change. */ DEBUG("aes key at %p: update apqns to match type %d", aes_key, type); free(aes_key->apqns); aes_key->apqns = NULL; aes_key->napqns = 0; aes_key->apqns_set = 0; rc = alloc_apqns_from_mkvp(pkeyfd, &(aes_key->apqns), &(aes_key->napqns), aes_key->mkvp, type); if (rc != 0) goto ret; DEBUG("aes key at %p: %lu apqns set", aes_key, aes_key->napqns); aes_key->apqns_set = 1; } DEBUG("aes key at %p: type set to %d", aes_key, type); aes_key->type = type; aes_key->type_set = 1; rc = 0; ret: rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_key_set_flags(struct zpc_aes_key *aes_key, unsigned int flags) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); if (aes_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } DEBUG("aes key at %p: flags set to %u", aes_key, flags); aes_key->flags = flags; aes_key->flags_set = 1; rc = 0; ret: rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } /* * Associate aes_key to all apqns of the given mkvp. */ int zpc_aes_key_set_mkvp(struct zpc_aes_key *aes_key, const char *mkvp) { u8 mkvpbuf[MAX_MKVPLEN]; size_t mkvpbuflen; int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); if (aes_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } if (mkvp == NULL) { DEBUG("aes key at %p: apqns unset", aes_key); free(aes_key->apqns); aes_key->apqns = NULL; aes_key->napqns = 0; aes_key->apqns_set = 0; rc = 0; goto ret; } mkvpbuflen = sizeof(mkvpbuf); if (hexstr2buf(mkvpbuf, &mkvpbuflen, mkvp)) { rc = ZPC_ERROR_PARSE; goto ret; } if (mkvpbuflen != 8 && mkvpbuflen != 16 && mkvpbuflen != 32) { rc = ZPC_ERROR_MKVPLEN; goto ret; } if (aes_key->type_set != 1) { rc = ZPC_ERROR_KEYTYPENOTSET; goto ret; } DEBUG("aes key at %p: apqns unset", aes_key); free(aes_key->apqns); aes_key->apqns = NULL; aes_key->napqns = 0; aes_key->apqns_set = 0; if (aes_key->type == ZPC_AES_KEY_TYPE_PVSECRET) { rc = 0; /* function has no effect */ goto ret; } rc = alloc_apqns_from_mkvp(pkeyfd, &(aes_key->apqns), &(aes_key->napqns), mkvpbuf, aes_key->type); if (rc != 0) goto ret; DEBUG("aes key at %p: mkvp and %lu apqns set", aes_key, aes_key->napqns); memcpy(aes_key->mkvp, mkvpbuf, mkvpbuflen); aes_key->apqns_set = 1; aes_key->mkvp_set = 1; ret: rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } /* * Associate aes_key to a list NULL terminated list of apqns. */ int zpc_aes_key_set_apqns(struct zpc_aes_key *aes_key, const char *apqns[]) { unsigned int card, domain; size_t i, napqns; int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); if (apqns == NULL) { DEBUG("aes key at %p: apqns unset", aes_key); free(aes_key->apqns); aes_key->apqns = NULL; aes_key->napqns = 0; aes_key->apqns_set = 0; rc = 0; goto ret; } if (aes_key->type == ZPC_AES_KEY_TYPE_PVSECRET) { rc = 0; /* function has no effect */ goto ret; } for (napqns = 0; apqns[napqns] != NULL; napqns++); if (aes_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } DEBUG("aes key at %p: apqns unset", aes_key); free(aes_key->apqns); aes_key->apqns = NULL; aes_key->napqns = 0; aes_key->apqns_set = 0; DEBUG("aes key at %p: mkvp unset", aes_key); memset(aes_key->mkvp, 0, sizeof(aes_key->mkvp)); aes_key->mkvplen = 0; aes_key->mkvp_set = 0; if (napqns == 0) { rc = 0; /* nothing to do */ goto ret; } aes_key->apqns = calloc(napqns, sizeof(*(aes_key->apqns))); if (aes_key->apqns == NULL) return ZPC_ERROR_MALLOC; for (i = 0; i < napqns; i++) { rc = sscanf(apqns[i], " %x.%x ", &card, &domain); if (rc != 2) { rc = ZPC_ERROR_PARSE; goto ret; } aes_key->apqns[i].card = card; aes_key->apqns[i].domain = domain; } DEBUG("aes key at %p: %lu apqns set", aes_key, aes_key->napqns); aes_key->napqns = napqns; aes_key->apqns_set = 1; rc = 0; ret: if (rc != 0) { free(aes_key->apqns); aes_key->apqns = NULL; aes_key->napqns = 0; } rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_key_import_clear(struct zpc_aes_key *aes_key, const unsigned char *key) { struct pkey_clr2seck2 clr2seck2; unsigned int flags, hdr_to_add = 0; int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (key == NULL) { rc = ZPC_ERROR_ARG2NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); if (aes_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } if (aes_key->apqns_set != 1) { rc = ZPC_ERROR_APQNSNOTSET; goto ret; } if (aes_key->keysize_set != 1) { rc = ZPC_ERROR_KEYSIZENOTSET; goto ret; } if (aes_key->type_set != 1) { rc = ZPC_ERROR_KEYTYPENOTSET; goto ret; } if (aes_key->type == ZPC_AES_KEY_TYPE_PVSECRET) { rc = ZPC_ERROR_KEYTYPE; goto ret; } flags = aes_key->flags_set == 1 ? aes_key->flags : 0; memset(&aes_key->cur, 0, sizeof(aes_key->cur)); memset(&aes_key->old, 0, sizeof(aes_key->old)); aes_key->key_set = 0; memset(&clr2seck2, 0, sizeof(clr2seck2)); clr2seck2.apqns = aes_key->apqns; clr2seck2.apqn_entries = aes_key->napqns; clr2seck2.type = aes_key->type; if (aes_key->type == ZPC_AES_KEY_TYPE_EP11) clr2seck2.type = TOKVER_EP11_AES_WITH_HEADER; /* 0x06 */ clr2seck2.size = aes_key->keysize; clr2seck2.keygenflags = flags; memcpy(&clr2seck2.clrkey, key, aes_key->keysize / 8); clr2seck2.key = aes_key->cur.sec; clr2seck2.keylen = sizeof(aes_key->cur.sec); /* * If it's an EP11 key, we first try to import the clear key as a type 6 key * (TOKVER_EP11_AES_WITH_HEADER). This may fail on older kernels. If it * fails, we try to import as a type 3 (TOKVER_EP11_AES) key and add the * type 6 header manually below. If successful, we end up with a type 6 * key in both cases. */ rc = ioctl(pkeyfd, PKEY_CLR2SECK2, &clr2seck2); if (rc != 0) { DEBUG("ioctl PKEY_CLR2SECK2 for %s key returned %d", aes_key->type == ZPC_AES_KEY_TYPE_EP11 ? "ep11 aes type 6" : "cca", rc); if (aes_key->type == ZPC_AES_KEY_TYPE_EP11) { /* Retry with a type 3 key */ clr2seck2.type = TOKVER_EP11_AES; /* 0x03 */ rc = ioctl(pkeyfd, PKEY_CLR2SECK2, &clr2seck2); DEBUG("ioctl PKEY_CLR2SECK2 for aes ep11 type 3 key returned %d", rc); if (rc != 0) { rc = ZPC_ERROR_IOCTLCLR2SECK2; goto ret; } hdr_to_add = 1; } else { rc = ZPC_ERROR_IOCTLCLR2SECK2; goto ret; } } aes_key->cur.seclen = clr2seck2.keylen; rc = aes_key_clr2prot(aes_key, key, aes_key->keysize / 8); if (rc) { rc = aes_key_sec2prot(aes_key, AES_KEY_SEC_CUR); if (rc) { goto ret; } } if (aes_key->type == ZPC_AES_KEY_TYPE_EP11 && hdr_to_add) { rc = aes_key_add_ep11_header(aes_key); if (rc) goto ret; } if (aes_key->type == ZPC_AES_KEY_TYPE_EP11 && aes_key_blob_has_a_session(aes_key)) DEBUG("This aes ep11 key has a session id"); else DEBUG("This aes ep11 key has no session id"); DEBUG("aes key at %p: key set", aes_key); aes_key->key_set = 1; rc = 0; ret: if (rc != 0) memset(&aes_key->cur, 0, sizeof(aes_key->cur)); rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); memzero_secure(&clr2seck2.clrkey, sizeof(clr2seck2.clrkey)); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_key_export(struct zpc_aes_key *aes_key, unsigned char *buf, size_t *buflen) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (buflen == NULL) { rc = ZPC_ERROR_ARG3NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); if (aes_key->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } rc = aes_key_check(aes_key); if (rc) goto ret; if (buf == NULL) { *buflen = aes_key->cur.seclen; rc = 0; goto ret; } if (*buflen < aes_key->cur.seclen) { *buflen = aes_key->cur.seclen; rc = ZPC_ERROR_SMALLOUTBUF; goto ret; } *buflen = aes_key->cur.seclen; memcpy(buf, aes_key->cur.sec, *buflen); rc = 0; ret: rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_key_import(struct zpc_aes_key *aes_key, const unsigned char *buf, size_t buflen) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { return ZPC_ERROR_DEVPKEY; } if (aes_key == NULL) { return ZPC_ERROR_ARG1NULL; } if (buf == NULL) { return ZPC_ERROR_ARG2NULL; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); if (aes_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } if (aes_key->type != ZPC_AES_KEY_TYPE_PVSECRET) { if (buflen < MIN_SECURE_KEY_SIZE || buflen > MAX_SECURE_KEY_SIZE) { rc = ZPC_ERROR_ARG3RANGE; goto ret; } } else { if (buflen != UV_SECRET_ID_LEN) { rc = ZPC_ERROR_ARG3RANGE; goto ret; } } if (aes_key->keysize_set != 1) { rc = ZPC_ERROR_KEYSIZENOTSET; goto ret; } if (aes_key->type_set != 1) { rc = ZPC_ERROR_KEYTYPENOTSET; goto ret; } if (aes_key->type == ZPC_AES_KEY_TYPE_EP11 && !is_ep11_aes_key_with_header(buf, buflen) && !is_ep11_aes_key(buf, buflen)) { rc = ZPC_ERROR_AES_NO_EP11_SECUREKEY_TOKEN; goto ret; } if (aes_key->type == ZPC_AES_KEY_TYPE_CCA_DATA && !is_cca_aes_data_key(buf, buflen)) { rc = ZPC_ERROR_AES_NO_CCA_DATAKEY_TOKEN; goto ret; } if (aes_key->type == ZPC_AES_KEY_TYPE_CCA_CIPHER && !is_cca_aes_cipher_key(buf, buflen)) { rc = ZPC_ERROR_AES_NO_CCA_CIPHERKEY_TOKEN; goto ret; } if (aes_key->type != ZPC_AES_KEY_TYPE_PVSECRET) { if (!aes_key_blob_has_valid_mkvp(aes_key, buf, buflen)) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } if (!aes_key_blob_is_pkey_extractable(aes_key, buf, buflen)) { rc = ZPC_ERROR_BLOB_NOT_PKEY_EXTRACTABLE; goto ret; } } else { if (aes_key_blob_is_valid_pvsecret_id(aes_key, buf) != 0) { rc = ZPC_ERROR_PVSECRET_ID_NOT_FOUND_IN_UV; goto ret; } } memset(aes_key->cur.sec, 0, sizeof(aes_key->cur.sec)); memcpy(aes_key->cur.sec, buf, buflen); aes_key->cur.seclen = buflen; aes_key->key_set = 1; if (aes_key->type == ZPC_AES_KEY_TYPE_EP11 && is_ep11_aes_key(buf, buflen)) { rc = aes_key_add_ep11_header(aes_key); if (rc) goto ret; } rc = 0; ret: rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_key_generate(struct zpc_aes_key *aes_key) { struct pkey_genseck2 genseck2; struct pkey_genprotk genprotk; unsigned int flags, hdr_to_add = 0; int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); if (aes_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } if (aes_key->type == ZPC_AES_KEY_TYPE_PVSECRET) { rc = ZPC_ERROR_KEYTYPE; goto ret; } if (aes_key->keysize_set != 1) { rc = ZPC_ERROR_KEYSIZENOTSET; goto ret; } if (aes_key->apqns_set != 1) { /* Generate random protected key only. */ memset(&genprotk, 0, sizeof(genprotk)); switch (aes_key->keysize) { case 128: genprotk.keytype = PKEY_KEYTYPE_AES_128; break; case 192: genprotk.keytype = PKEY_KEYTYPE_AES_192; break; case 256: genprotk.keytype = PKEY_KEYTYPE_AES_256; break; default: rc = ZPC_ERROR_KEYSIZE; goto ret; break; } rc = ioctl(pkeyfd, PKEY_GENPROTK, &genprotk); if (rc != 0) { rc = ZPC_ERROR_IOCTLGENPROTK; goto ret; } DEBUG("aes key at %p: key set to generated protected key", aes_key); memcpy(&aes_key->prot, &genprotk.protkey, sizeof(aes_key->prot)); aes_key->rand_protk = 1; aes_key->key_set = 1; rc = 0; goto ret; } if (aes_key->type_set != 1) { rc = ZPC_ERROR_KEYTYPENOTSET; goto ret; } flags = aes_key->flags_set == 1 ? aes_key->flags : 0; memset(&aes_key->cur, 0, sizeof(aes_key->cur)); memset(&aes_key->old, 0, sizeof(aes_key->old)); aes_key->key_set = 0; memset(&genseck2, 0, sizeof(genseck2)); genseck2.apqns = aes_key->apqns; genseck2.apqn_entries = aes_key->napqns; genseck2.type = aes_key->type; if (aes_key->type == ZPC_AES_KEY_TYPE_EP11) genseck2.type = TOKVER_EP11_AES_WITH_HEADER; /* 0x06 */ genseck2.size = aes_key->keysize; genseck2.keygenflags = flags; genseck2.key = aes_key->cur.sec; genseck2.keylen = sizeof(aes_key->cur.sec); /* * If it's an EP11 key, we first try to generate a type 6 key * (TOKVER_EP11_AES_WITH_HEADER). This may fail on older kernels. If it * fails, we try to generate a type 3 (TOKVER_EP11_AES) key and add the * type 6 header manually below. If successful, we end up with a type 6 * key in both cases. */ rc = ioctl(pkeyfd, PKEY_GENSECK2, &genseck2); if (rc != 0) { DEBUG("ioctl PKEY_GENSECK2 for %s key returned %d", aes_key->type == ZPC_AES_KEY_TYPE_EP11 ? "ep11 aes type 6" : "cca", rc); if (aes_key->type == ZPC_AES_KEY_TYPE_EP11) { /* Retry to generate a type 3 key */ genseck2.type = TOKVER_EP11_AES; /* 0x03 */; rc = ioctl(pkeyfd, PKEY_GENSECK2, &genseck2); DEBUG("ioctl PKEY_GENSECK2 for aes ep11 type 3 key returned %d", rc); if (rc != 0) { rc = ZPC_ERROR_IOCTLGENSECK2; goto ret; } hdr_to_add = 1; } else { rc = ZPC_ERROR_IOCTLGENSECK2; goto ret; } } aes_key->cur.seclen = genseck2.keylen; rc = aes_key_sec2prot(aes_key, AES_KEY_SEC_CUR); if (rc) goto ret; if (aes_key->type == ZPC_AES_KEY_TYPE_EP11 && hdr_to_add) { rc = aes_key_add_ep11_header(aes_key); if (rc) goto ret; } if (aes_key->type == ZPC_AES_KEY_TYPE_EP11) { if (aes_key_blob_has_a_session(aes_key)) DEBUG("This aes ep11 key has a session id"); else DEBUG("This aes ep11 key has no session id"); } DEBUG("aes key at %p: key set to generated secure key", aes_key); aes_key->key_set = 1; rc = 0; ret: if (rc != 0) memset(&aes_key->cur, 0, sizeof(aes_key->cur)); rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_key_reencipher(struct zpc_aes_key *aes_key, int method) { struct aes_key reenc; unsigned int seckeylen; target_t target; int rv, rc = ZPC_ERROR_APQNSNOTSET; size_t i; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&aes_key->lock); assert(rv == 0); if (aes_key->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (aes_key->key_set == 0) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } if (aes_key->keysize_set == 0) { rc = ZPC_ERROR_KEYSIZENOTSET; goto ret; } if (aes_key->type_set == 0) { rc = ZPC_ERROR_KEYTYPENOTSET; goto ret; } if (aes_key->type == ZPC_AES_KEY_TYPE_PVSECRET) { /* reencipher not applicable for pvsecrets */ rc = ZPC_ERROR_KEYTYPE; goto ret; } if (aes_key->apqns_set == 0 || aes_key->napqns == 0) { rc = ZPC_ERROR_APQNSNOTSET; goto ret; } memcpy(&reenc, &aes_key->cur, sizeof(reenc)); switch (aes_key->type) { case ZPC_AES_KEY_TYPE_CCA_DATA: /* fall-through */ case ZPC_AES_KEY_TYPE_CCA_CIPHER: /* fall-through */ seckeylen = aes_key->type == ZPC_AES_KEY_TYPE_CCA_DATA ? AESDATA_KEY_SIZE : AESCIPHER_KEY_SIZE; rv = pthread_mutex_lock(&ccalock); assert(rv == 0); for (i = 0; i < aes_key->napqns; i++) { rc = select_cca_adapter(&cca, aes_key->apqns[i].card, aes_key->apqns[i].domain, true); if (rc) continue; rc = key_token_change(&cca, reenc.sec, seckeylen, method == ZPC_AES_KEY_REENCIPHER_OLD_TO_CURRENT ? METHOD_OLD_TO_CURRENT : METHOD_CURRENT_TO_NEW, true); if (rc == 0) break; } rv = pthread_mutex_unlock(&ccalock); assert(rv == 0); break; case ZPC_AES_KEY_TYPE_EP11: if (method != ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW) { rc = ZPC_ERROR_NOTSUP; goto ret; } rv = pthread_mutex_lock(&ep11lock); assert(rv == 0); for (i = 0; i < aes_key->napqns; i++) { rc = get_ep11_target_for_apqn(&ep11, aes_key->apqns[i].card, aes_key->apqns[i].domain, &target, true); if (rc) continue; /* Note that the secure key is a TOKVER_EP11_AES_WITH_HEADER and has a * 16-byte ep11kblob_header prepended before the actual secure key blob. * For reencipher we have to skip this prepended hdr and provide the * key blob directly. */ rc = reencipher_ep11_key(&ep11, target, aes_key->apqns[i].card, aes_key->apqns[i].domain, reenc.sec + sizeof(struct ep11kblob_header), aes_key->cur.seclen - sizeof(struct ep11kblob_header), true); free_ep11_target_for_apqn(&ep11, target); if (rc == 0) break; } rv = pthread_mutex_unlock(&ep11lock); assert(rv == 0); break; default: rc = ZPC_ERROR_KEYTYPE; } if (rc) goto ret; memcpy(&aes_key->old, &aes_key->cur, sizeof(aes_key->old)); memcpy(&aes_key->cur, &reenc, sizeof(aes_key->cur)); rc = 0; ret: rv = pthread_mutex_unlock(&aes_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } void zpc_aes_key_free(struct zpc_aes_key **aes_key) { int rv, free_obj = 0; UNUSED(rv); if (aes_key == NULL) return; if (*aes_key == NULL) return; rv = pthread_mutex_lock(&(*aes_key)->lock); assert(rv == 0); if ((*aes_key)->refcount == 0) goto ret; (*aes_key)->refcount--; DEBUG("aes key at %p: refcount %llu", *aes_key, (*aes_key)->refcount); if ((*aes_key)->refcount == 0) { free_obj = 1; __aes_key_reset(*aes_key); } ret: rv = pthread_mutex_unlock(&(*aes_key)->lock); assert(rv == 0); if (free_obj == 1) { rv = pthread_mutex_destroy(&(*aes_key)->lock); assert(rv == 0); free(*aes_key); } *aes_key = NULL; DEBUG("return"); } /* * Reset everything that was set after allocation. * Caller must hold aes_key's wr lock. */ static void __aes_key_reset(struct zpc_aes_key *aes_key) { assert(aes_key != NULL); memset(&aes_key->cur, 0, sizeof(aes_key->cur)); memset(&aes_key->old, 0, sizeof(aes_key->old)); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); aes_key->key_set = 0; aes_key->keysize = 0; aes_key->keysize_set = 0; aes_key->flags = 0; aes_key->flags_set = 0; aes_key->type = 0; aes_key->type_set = 0; memset(aes_key->mkvp, 0, sizeof(aes_key->mkvp)); aes_key->mkvplen = 0; aes_key->mkvp_set = 0; free(aes_key->apqns); aes_key->apqns = NULL; aes_key->napqns = 0; aes_key->apqns_set = 0; aes_key->rand_protk = 0; aes_key->refcount = 1; } u16 aesprotkeylen_from_pvsectype(u16 pvsectype) { switch (pvsectype) { case ZPC_AES_SECRET_AES_128: return 16 + 32; case ZPC_AES_SECRET_AES_192: return 24 + 32; case ZPC_AES_SECRET_AES_256: return 32 + 32; default: break; } return 0; } void aes_key_make_uvrsecrettoken(struct zpc_aes_key *aes_key, const unsigned char *id, unsigned char *buf) { struct uvrsecrettoken *clrtok = (struct uvrsecrettoken *)buf; clrtok->version = TOKVER_UV_SECRET; switch (aes_key->keysize) { case 128: clrtok->secret_type = ZPC_AES_SECRET_AES_128; break; case 192: clrtok->secret_type = ZPC_AES_SECRET_AES_192; break; default: clrtok->secret_type = ZPC_AES_SECRET_AES_256; break; } clrtok->secret_len = aesprotkeylen_from_pvsectype(clrtok->secret_type); memcpy(clrtok->secret_id, id, UV_SECRET_ID_LEN); } /* * Verify that a given pvsecret ID is a valid ID on this system, i.e. an UV * secret exists with this ID and has the expected key length. */ int aes_key_blob_is_valid_pvsecret_id(struct zpc_aes_key *aes_key, const unsigned char *id) { struct pkey_verifykey2 io; unsigned char buf[sizeof(struct uvrsecrettoken)] = { 0, }; int rc; aes_key_make_uvrsecrettoken(aes_key, id, buf); memset(&io, 0, sizeof(io)); io.key = buf; io.keylen = sizeof(struct uvrsecrettoken); errno = 0; rc = ioctl(pkeyfd, PKEY_VERIFYKEY2, &io); if (rc != 0) { DEBUG("aes key at %p: PKEY_VERIFYKEY2 ioctl failed, errno = %d", aes_key, errno); return ZPC_ERROR_IOCTLVERIFYKEY2; } return 0; } /* * (Re)derive protected key from a retrievable secret ID. * Caller must hold aes_key's wr lock. */ int aes_key_pvsec2prot(struct zpc_aes_key *aes_key) { struct pkey_kblob2pkey3 io; unsigned char buf[sizeof(struct uvrsecrettoken)] = { 0, }; int rc; aes_key_make_uvrsecrettoken(aes_key, aes_key->cur.sec, buf); memset(&io, 0, sizeof(io)); io.key = buf; io.keylen = sizeof(struct uvrsecrettoken); io.pkeytype = aes_key->type; io.pkeylen = sizeof(aes_key->prot.protkey); io.pkey = (unsigned char *)&aes_key->prot.protkey; errno = 0; rc = ioctl(pkeyfd, PKEY_KBLOB2PROTK3, &io); if (rc != 0) { DEBUG("aes key at %p: PKEY_KBLOB2PROTK3 ioctl failed, errno = %d", aes_key, errno); return ZPC_ERROR_IOCTLBLOB2PROTK3; } return 0; } /* * (Re)derive protected key from a secure key. * Caller must hold aes_key's wr lock. */ int aes_key_sec2prot_without_header(struct zpc_aes_key *aes_key, enum aes_key_sec sec) { struct pkey_kblob2pkey2 io; struct aes_key *key = NULL; int rc, i; assert(sec == AES_KEY_SEC_OLD || sec == AES_KEY_SEC_CUR); if (sec == AES_KEY_SEC_CUR) key = &aes_key->cur; else if (sec == AES_KEY_SEC_OLD) key = &aes_key->old; assert(key != NULL); memset(&io, 0, sizeof(io)); io.key = key->sec; io.keylen = key->seclen; io.apqns = aes_key->apqns; io.apqn_entries = aes_key->napqns; for (i = 0; i < 10; i++) { rc = ioctl(pkeyfd, PKEY_KBLOB2PROTK2, &io); if (rc == 0 || (errno != -EBUSY && errno != -EAGAIN)) break; sleep(1); } if (rc != 0) return ZPC_ERROR_IOCTLBLOB2PROTK2; memcpy(&aes_key->prot, &io.protkey, sizeof(aes_key->prot)); return 0; } /* * Currently there is no ioctl to convert a TOKVER_EP11_AES_WITH_HEADER. So * prepare an overlay over the session id field and convert it as a * TOKVER_EP11_AES. Then restore the session id field. */ int aes_key_sec2prot_with_header(struct zpc_aes_key *aes_key, enum aes_key_sec sec) { struct pkey_kblob2pkey2 io; struct aes_key *key = NULL; int rc, i; unsigned char temp[sizeof(struct ep11kblob_header)]; struct ep11kblob_header *hdr; assert(sec == AES_KEY_SEC_OLD || sec == AES_KEY_SEC_CUR); if (sec == AES_KEY_SEC_CUR) key = &aes_key->cur; else if (sec == AES_KEY_SEC_OLD) key = &aes_key->old; assert(key != NULL); /* * First try the ioctl with the version 6 key blob. This also sends the * session id to the pkey kernel module. */ memset(&io, 0, sizeof(io)); io.key = key->sec; io.keylen = key->seclen; io.apqns = aes_key->apqns; io.apqn_entries = aes_key->napqns; for (i = 0; i < 10; i++) { rc = ioctl(pkeyfd, PKEY_KBLOB2PROTK2, &io); if (rc == 0 || (errno != -EBUSY && errno != -EAGAIN)) break; sleep(1); } if (rc == 0) goto done; /* * Version 6 key blob ioctl failed, most likely there is no kernel support * for type 6 keys. Now check if this key is session bound: if it has a * session id, then we cannot convert this key without overlaying, i.e. * destroying, the session id. If not, retry the ioctl with a type 3 key * blob by overlaying the session id. */ if (is_session_bound(key->sec, key->seclen)) return ZPC_ERROR_IOCTLBLOB2PROTK2; /* * This key is not session bound. Retry as version 3 key blob by overlaying * the session id field with the key header. */ memcpy(temp, key->sec + 16, 16); // save first 16 bytes session id memcpy(key->sec + 16, key->sec, 16); // overlay hdr in session id hdr = (struct ep11kblob_header *)(key->sec + 16); hdr->version = TOKEN_VERSION_EP11_AES; // set key type TOKVER_EP11_AES hdr->len = key->seclen - 16; // adjust length memset(&io, 0, sizeof(io)); io.key = key->sec + 16; io.keylen = key->seclen - 16; io.apqns = aes_key->apqns; io.apqn_entries = aes_key->napqns; for (i = 0; i < 10; i++) { rc = ioctl(pkeyfd, PKEY_KBLOB2PROTK2, &io); if (rc == 0 || (errno != -EBUSY && errno != -EAGAIN)) break; sleep(1); } memcpy(key->sec + 16, temp, 16); // restore session id in any case if (rc != 0) return ZPC_ERROR_IOCTLBLOB2PROTK2; done: memcpy(&aes_key->prot, &io.protkey, sizeof(aes_key->prot)); return 0; } /* * (Re)derive protected key from a secure key. * Caller must hold aes_key's wr lock. */ int aes_key_sec2prot(struct zpc_aes_key *aes_key, enum aes_key_sec sec) { struct aes_key *key = NULL; size_t keylen; switch (aes_key->type) { case ZPC_AES_KEY_TYPE_EP11: assert(sec == AES_KEY_SEC_OLD || sec == AES_KEY_SEC_CUR); if (sec == AES_KEY_SEC_CUR) { key = &aes_key->cur; keylen = aes_key->cur.seclen; } else { key = &aes_key->old; keylen = aes_key->old.seclen; } assert(key != NULL); if (is_ep11_aes_key_with_header(key->sec, keylen)) return aes_key_sec2prot_with_header(aes_key, sec); else return aes_key_sec2prot_without_header(aes_key, sec); case ZPC_AES_KEY_TYPE_PVSECRET: return aes_key_pvsec2prot(aes_key); default: return aes_key_sec2prot_without_header(aes_key, sec); } } int aes_key_clr2prot(struct zpc_aes_key *aes_key, const unsigned char *key, unsigned int keylen) { struct pkey_kblob2pkey3 io; unsigned char buf[sizeof(struct clearkeytoken) + 32]; struct clearkeytoken *clrtok = (struct clearkeytoken *)&buf; int rc; memset(buf, 0, sizeof(buf)); clrtok->version = 0x02; switch (keylen) { case 16: clrtok->keytype = PKEY_KEYTYPE_AES_128; break; case 24: clrtok->keytype = PKEY_KEYTYPE_AES_192; break; default: clrtok->keytype = PKEY_KEYTYPE_AES_256; break; } memcpy(clrtok->clearkey, key, keylen); clrtok->len = keylen; memset(&io, 0, sizeof(io)); io.key = buf; io.keylen = sizeof(struct clearkeytoken) + keylen; io.apqns = aes_key->apqns; io.apqn_entries = aes_key->napqns; io.pkeytype = aes_key->type; io.pkeylen = sizeof(aes_key->prot.protkey); io.pkey = (unsigned char *)&aes_key->prot.protkey; rc = ioctl(pkeyfd, PKEY_KBLOB2PROTK3, &io); if (rc != 0) { return ZPC_ERROR_IOCTLBLOB2PROTK3; } return 0; } int aes_key_check(const struct zpc_aes_key *aes_key) { if (aes_key->key_set != 1) return ZPC_ERROR_KEYNOTSET; if (aes_key->keysize_set != 1) return ZPC_ERROR_KEYSIZENOTSET; /* Random protected keys have no type. */ if (aes_key->rand_protk == 0 && aes_key->type_set != 1) return ZPC_ERROR_KEYTYPENOTSET; return 0; } static int aes_key_blob_has_valid_mkvp(struct zpc_aes_key *aes_key, const unsigned char *buf, size_t buflen) { const unsigned char *mkvp, *keytoken; unsigned int mkvp_len; u64 mkvp_value; if (aes_key->mkvp_set == 0) return 1; /* cannot judge */ keytoken = buf; if (is_ep11_aes_key_with_header(buf, buflen)) keytoken += sizeof(struct ep11kblob_header); switch (aes_key->type) { case ZPC_AES_KEY_TYPE_CCA_DATA: mkvp_value = ((struct aesdatakeytoken *)keytoken)->mkvp; mkvp = (const unsigned char *)&mkvp_value; mkvp_len = MKVP_LEN_CCA; break; case ZPC_AES_KEY_TYPE_CCA_CIPHER: mkvp = ((struct aescipherkeytoken *)keytoken)->kvp; mkvp_len = MKVP_LEN_CCA; break; default: mkvp = ((struct ep11keytoken *)keytoken)->wkvp; mkvp_len = MKVP_LEN_EP11; break; } if (memcmp(aes_key->mkvp, mkvp, mkvp_len) == 0) return 1; return 0; } static int aes_key_blob_is_pkey_extractable(struct zpc_aes_key *aes_key, const unsigned char *buf, size_t buflen) { const unsigned char *keytoken; u16 kmf1; u64 attr; keytoken = buf; if (is_ep11_aes_key_with_header(buf, buflen)) keytoken += sizeof(struct ep11kblob_header); switch (aes_key->type) { case ZPC_AES_KEY_TYPE_CCA_DATA: /* No check possible. The flags field in struct aesdatakeytoken * does not contain a CCA_XPRTCPAC indication. */ return 1; case ZPC_AES_KEY_TYPE_CCA_CIPHER: kmf1 = ((struct aescipherkeytoken *)keytoken)->kmf1; if (kmf1 & KMF1_XPRT_CPAC) return 1; break; case ZPC_AES_KEY_TYPE_EP11: attr = ((struct ep11keytoken *)keytoken)->attr; if (attr & XCP_BLOB_PROTKEY_EXTRACTABLE) return 1; break; default: break; } return 0; } static int aes_key_add_ep11_header(struct zpc_aes_key *aes_key) { struct ep11kblob_header *ep11hdr; if (aes_key->cur.seclen + sizeof(struct ep11kblob_header) > sizeof(aes_key->cur.sec)) return 1; memset(aes_key->cur.sec, 0, sizeof(struct ep11kblob_header)); memmove(aes_key->cur.sec + sizeof(struct ep11kblob_header), aes_key->cur.sec, aes_key->cur.seclen); memset(aes_key->cur.sec + sizeof(struct ep11kblob_header), 0, 32); ep11hdr = (struct ep11kblob_header *)aes_key->cur.sec; ep11hdr->len = sizeof(struct ep11kblob_header) + aes_key->cur.seclen; ep11hdr->version = TOKVER_EP11_AES_WITH_HEADER; ep11hdr->bitlen = aes_key->keysize; aes_key->cur.seclen = ep11hdr->len; return 0; } static int aes_key_blob_has_a_session(struct zpc_aes_key *aes_key) { u8 session[32] = { 0, }; if (memcmp(aes_key->cur.sec + sizeof(struct ep11kblob_header), session, 32) == 0) return 0; return 1; } libzpc-1.3.0/src/aes_key_local.h000066400000000000000000000025521475140344100165370ustar00rootroot00000000000000#ifndef AES_KEY_LOCAL_H # define AES_KEY_LOCAL_H /* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ # include "misc.h" # include "zpc/aes_key.h" # include # include /* * Internal aes_key interface. */ /* Maximum size of secure key blob. */ # define MAX_AESKEYBLOBSIZE 512 enum aes_key_sec { AES_KEY_SEC_CUR = 0, AES_KEY_SEC_OLD = 1, }; struct aes_key { unsigned char sec[MAX_AESKEYBLOBSIZE]; size_t seclen; /* byte-length of secure key blob */ }; struct zpc_aes_key { struct aes_key cur; /* old secure key is needed when */ struct aes_key old; /* current is not usable yet */ struct pkey_protkey prot; /* protected key derived from sec */ int key_set; int keysize; int keysize_set; unsigned int flags; int flags_set; int type; int type_set; u8 mkvp[MAX_MKVPLEN]; size_t mkvplen; /* byte-length of mkvp */ int mkvp_set; struct pkey_apqn *apqns; size_t napqns; /* elements in apqns */ int apqns_set; int rand_protk; unsigned long long refcount; pthread_mutex_t lock; }; int aes_key_sec2prot(struct zpc_aes_key *, enum aes_key_sec sec); int aes_key_check(const struct zpc_aes_key *); int aes_key_clr2prot(struct zpc_aes_key *, const unsigned char *key, unsigned int keylen); #endif libzpc-1.3.0/src/aes_xts.c000066400000000000000000000364701475140344100154140ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include "zpc/aes_xts.h" #include "zpc/error.h" #include "aes_xts_local.h" #include "aes_key_local.h" #include "cpacf.h" #include "globals.h" #include "misc.h" #include "debug.h" #include "zkey/pkey.h" #include #include #include #include #include static int __aes_xts_set_iv(struct zpc_aes_xts *, const u8 *); static int __aes_xts_set_intermediate_iv(struct zpc_aes_xts *, const u8 iv[16]); static int __aes_xts_crypt(struct zpc_aes_xts *, u8 *, const u8 *, size_t, unsigned long); static void __aes_xts_reset(struct zpc_aes_xts *); static void __aes_xts_reset_iv(struct zpc_aes_xts *); int zpc_aes_xts_alloc(struct zpc_aes_xts **aes_xts) { struct zpc_aes_xts *new_aes_xts = NULL; int rc; if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.aes_xts) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_xts == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } new_aes_xts = calloc(1, sizeof(*new_aes_xts)); if (new_aes_xts == NULL) { rc = ZPC_ERROR_MALLOC; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } DEBUG("aes-xts context at %p: allocated", new_aes_xts); *aes_xts = new_aes_xts; rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_xts_set_key(struct zpc_aes_xts *aes_xts, struct zpc_aes_key *aes_key1, struct zpc_aes_key *aes_key2) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.aes_xts) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_xts == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key1 == NULL || aes_key2 == NULL) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("aes-xts context at %p: key unset", aes_xts); __aes_xts_reset(aes_xts); rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (aes_key1 == aes_key2) { rc = ZPC_ERROR_KEYSEQUAL; goto ret; } rv = pthread_mutex_lock(&aes_key1->lock); assert(rv == 0); rv = pthread_mutex_lock(&aes_key2->lock); assert(rv == 0); rc = aes_key_check(aes_key1); if (rc) goto ret; rc = aes_key_check(aes_key2); if (rc) goto ret; if (aes_key1->keysize != aes_key2->keysize) { rc = ZPC_ERROR_KEYSIZE; goto ret; } if (aes_key1->keysize != 128 && aes_key1->keysize != 256) { rc = ZPC_ERROR_KEYSIZE; goto ret; } if (aes_xts->aes_key1 == aes_key1 && aes_xts->aes_key2 == aes_key2) { DEBUG("aes-xts context at %p: keys at %p and %p already set", aes_xts, aes_key1, aes_key2); rc = 0; /* nothing to do */ goto ret; } aes_key1->refcount++; DEBUG("aes key at %p: refcount %llu", aes_key1, aes_key1->refcount); aes_key2->refcount++; DEBUG("aes key at %p: refcount %llu", aes_key2, aes_key2->refcount); if (aes_xts->key_set) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("aes-xts context at %p: key unset", aes_xts); __aes_xts_reset(aes_xts); } /* Set new key. */ assert(!aes_xts->key_set); DEBUG("aes-xts context at %p: keys at %p and %p set", aes_xts, aes_key1, aes_key2); memcpy(aes_xts->param_km, aes_key1->prot.protkey, AES_XTS_PROTKEYLEN(aes_key1->keysize)); memcpy(aes_xts->param_pcc, aes_key2->prot.protkey, AES_XTS_PROTKEYLEN(aes_key2->keysize)); /* PCC uses the same function codes for 128 resp. 256 bit keys. */ aes_xts->fc = CPACF_KM_XTS_ENCRYPTED_AES_128 + (aes_key1->keysize - 128) / 64; aes_xts->aes_key1 = aes_key1; aes_xts->aes_key2 = aes_key2; aes_xts->key_set = 1; rc = 0; ret: rv = pthread_mutex_unlock(&aes_key1->lock); assert(rv == 0); rv = pthread_mutex_unlock(&aes_key2->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_xts_set_iv(struct zpc_aes_xts *aes_xts, const u8 * iv) { struct pkey_protkey *protkey; int rc, rv, i; u8 *param; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_xts) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_xts == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if (iv == NULL) { /* Unset iv */ DEBUG("aes-xts context at %p: iv unset", aes_xts); __aes_xts_reset_iv(aes_xts); aes_xts->iv_set = 0; rc = 0; goto ret; } if (aes_xts->key_set != 1) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } rc = -1; for (i = 0; i < 2 && rc != 0; i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_xts->aes_key2->prot; param = aes_xts->param_pcc; for (;;) { rc = __aes_xts_set_iv(aes_xts, iv); if (rc == 0) { break; } else { if (aes_xts->aes_key2->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_xts->aes_key2->lock); assert(rv == 0); DEBUG ("aes-xts context at %p: re-derive protected key from %s secure key from aes key at %p", aes_xts, i == 0 ? "current" : "old", aes_xts->aes_key2); rc = aes_key_sec2prot(aes_xts->aes_key2, i); memcpy(param, protkey->protkey, AES_XTS_PROTKEYLEN(aes_xts->aes_key2->keysize)); rv = pthread_mutex_unlock(&aes_xts->aes_key2->lock); assert(rv == 0); } if (rc) break; } } } if (rc) goto ret; DEBUG("aes-xts context at %p: iv set", aes_xts); aes_xts->iv_set = 1; ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_xts_get_intermediate_iv(struct zpc_aes_xts *aes_xts, unsigned char iv[16]) { int rc, off1; if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_xts) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_xts == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if (iv == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } if (aes_xts->iv_set != 1) { rc = ZPC_ERROR_IVNOTSET; goto ret; } off1 = AES_XTS_KM_XTSPARAM(aes_xts->aes_key1->keysize); memcpy(iv, aes_xts->param_km + off1, 16); rc = 0; ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_xts_set_intermediate_iv(struct zpc_aes_xts *aes_xts, const unsigned char iv[16]) { int rc; if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_xts) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_xts == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if (iv == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } if (aes_xts->key_set != 1) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } if (aes_xts->iv_set != 1) { rc = ZPC_ERROR_IVNOTSET; goto ret; } rc = __aes_xts_set_intermediate_iv(aes_xts, iv); if (rc) goto ret; aes_xts->iv_set = 1; DEBUG("aes-xts context at %p: intermediate iv set", aes_xts); ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_xts_encrypt(struct zpc_aes_xts *aes_xts, u8 * c, const u8 * m, size_t mlen) { struct pkey_protkey *protkey; unsigned long flags = 0; u8 *param; int rc, rv, i; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_xts) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_xts == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if ((mlen > 0 || m != NULL) && c == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } if ((mlen > 0 || c != NULL) && m == NULL) { rc = ZPC_ERROR_ARG3NULL; goto ret; } if (mlen < 16) { rc = ZPC_ERROR_MLEN; goto ret; } if (!aes_xts->key_set) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } if (!aes_xts->iv_set) { rc = ZPC_ERROR_IVNOTSET; goto ret; } rc = -1; for (i = 0; i < 2 && rc != 0; i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_xts->aes_key1->prot; param = aes_xts->param_km; for (;;) { rc = __aes_xts_crypt(aes_xts, c, m, mlen, flags); if (rc == 0) { break; } else { if (aes_xts->aes_key1->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_xts->aes_key1->lock); assert(rv == 0); DEBUG ("aes-xts context at %p: re-derive protected key" " from %s secure key from aes key at %p", aes_xts, i == 0 ? "current" : "old", aes_xts->aes_key1); rc = aes_key_sec2prot(aes_xts->aes_key1, i); memcpy(param, protkey->protkey, AES_XTS_PROTKEYLEN(aes_xts->aes_key1->keysize)); rv = pthread_mutex_unlock(&aes_xts->aes_key1->lock); assert(rv == 0); } if (rc) break; } } } ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_aes_xts_decrypt(struct zpc_aes_xts *aes_xts, u8 * m, const u8 * c, size_t clen) { struct pkey_protkey *protkey; unsigned long flags = CPACF_M; /* decrypt */ u8 *param; int rc, rv, i; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.aes_xts) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (aes_xts == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if ((clen > 0 || c != NULL) && m == NULL) { rc = ZPC_ERROR_ARG2NULL; goto ret; } if ((clen > 0 || m != NULL) && c == NULL) { rc = ZPC_ERROR_ARG3NULL; goto ret; } if (clen < 16) { rc = ZPC_ERROR_CLEN; goto ret; } if (!aes_xts->key_set) { rc = ZPC_ERROR_KEYNOTSET; goto ret; } if (!aes_xts->iv_set) { rc = ZPC_ERROR_IVNOTSET; goto ret; } rc = -1; for (i = 0; i < 2 && rc != 0; i++) { assert(i == AES_KEY_SEC_CUR || i == AES_KEY_SEC_OLD); protkey = &aes_xts->aes_key1->prot; param = aes_xts->param_km; for (;;) { rc = __aes_xts_crypt(aes_xts, m, c, clen, flags); if (rc == 0) { break; } else { if (aes_xts->aes_key1->rand_protk) { rc = ZPC_ERROR_PROTKEYONLY; goto ret; } if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&aes_xts->aes_key1->lock); assert(rv == 0); DEBUG ("aes-xts context at %p: re-derive protected key" " from %s secure key from aes key at %p", aes_xts, i == 0 ? "current" : "old", aes_xts->aes_key1); rc = aes_key_sec2prot(aes_xts->aes_key1, i); memcpy(param, protkey->protkey, AES_XTS_PROTKEYLEN(aes_xts->aes_key1->keysize)); rv = pthread_mutex_unlock(&aes_xts->aes_key1->lock); assert(rv == 0); } if (rc) break; } } } ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } void zpc_aes_xts_free(struct zpc_aes_xts **aes_xts) { if (aes_xts == NULL) return; if (*aes_xts == NULL) return; if ((*aes_xts)->key_set) { /* Decrease aes_key's refcount. */ zpc_aes_key_free(&(*aes_xts)->aes_key1); zpc_aes_key_free(&(*aes_xts)->aes_key2); (*aes_xts)->key_set = 0; __aes_xts_reset_iv(*aes_xts); (*aes_xts)->iv_set = 0; } __aes_xts_reset(*aes_xts); free(*aes_xts); *aes_xts = NULL; DEBUG("return"); } static int __aes_xts_set_iv(struct zpc_aes_xts *aes_xts, const u8 * iv) { int rc, cc, off1, off2; assert(aes_xts != NULL); assert(iv != NULL); assert(aes_xts->aes_key1 != NULL); assert(aes_xts->aes_key2 != NULL); assert(aes_xts->key_set == 1); /* set i */ off1 = AES_XTS_PCC_I(aes_xts->aes_key2->keysize); memcpy(aes_xts->param_pcc + off1, iv, 16); /* zero j, t, xtsparam */ off2 = AES_XTS_PCC_J(aes_xts->aes_key2->keysize); memset(aes_xts->param_pcc + off2, 0, 3 * 16); cc = cpacf_pcc(aes_xts->fc, aes_xts->param_pcc); /* Either incomplete processing or WKaVP mismatch. */ assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } off1 = AES_XTS_KM_XTSPARAM(aes_xts->aes_key1->keysize); off2 = AES_XTS_PCC_XTSPARAM(aes_xts->aes_key2->keysize); memcpy(aes_xts->param_km + off1, aes_xts->param_pcc + off2, 16); rc = 0; ret: return rc; } static int __aes_xts_set_intermediate_iv(struct zpc_aes_xts *aes_xts, const u8 iv[16]) { int rc, off1; assert(aes_xts != NULL); assert(iv != NULL); assert(aes_xts->aes_key1 != NULL); assert(aes_xts->aes_key2 != NULL); assert(aes_xts->key_set == 1); off1 = AES_XTS_KM_XTSPARAM(aes_xts->aes_key1->keysize); memcpy(aes_xts->param_km + off1, iv, 16); rc = 0; return rc; } static int __aes_xts_crypt(struct zpc_aes_xts *aes_xts, u8 * out, const u8 * in, size_t inlen, unsigned long flags) { int rc, cc; size_t rem; u8 tmp[16]; rem = inlen & 0xf; inlen &= ~(size_t)0xf; if (rem == 0) { cc = cpacf_km(aes_xts->fc | flags, aes_xts->param_km, out, in, inlen); assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } rc = 0; goto ret; } inlen -= 16; if (!(flags & CPACF_M)) { /* ciphertext-stealing (encrypt) */ cc = cpacf_km(aes_xts->fc | flags, aes_xts->param_km, out, in, inlen + 16); assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } memcpy(tmp, in + inlen + 16, rem); memcpy(tmp + rem, out + inlen + rem, 16 - rem); memcpy(out + inlen + 16, out + inlen, rem); cc = cpacf_km(aes_xts->fc | flags, aes_xts->param_km, out + inlen, tmp, 16); assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } } else if ((flags & CPACF_M)) { /* ciphertext-stealing (decrypt) */ u8 xtsparam[16], buf[16]; if (inlen) { cc = cpacf_km(aes_xts->fc | flags, aes_xts->param_km, out, in, inlen); assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } } memcpy(xtsparam, aes_xts->param_km + AES_XTS_KM_XTSPARAM(aes_xts->aes_key1->keysize), 16); cc = cpacf_km(aes_xts->fc | flags, aes_xts->param_km, buf, in + inlen, 16); assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } cc = cpacf_km(aes_xts->fc | flags, aes_xts->param_km, out + inlen, in + inlen, 16); assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } memcpy(tmp, in + inlen + 16, rem); memcpy(tmp + rem, out + inlen + rem, 16 - rem); memcpy(out + inlen + 16, out + inlen, rem); memcpy(aes_xts->param_km + AES_XTS_KM_XTSPARAM(aes_xts->aes_key1->keysize), xtsparam, 16); cc = cpacf_km(aes_xts->fc | flags, aes_xts->param_km, out + inlen, tmp, 16); assert(cc == 0 || cc == 2 || cc == 1); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } } rc = 0; ret: return rc; } static void __aes_xts_reset(struct zpc_aes_xts *aes_xts) { assert(aes_xts != NULL); memset(aes_xts->param_km, 0, sizeof(aes_xts->param_km)); memset(aes_xts->param_pcc, 0, sizeof(aes_xts->param_pcc)); __aes_xts_reset_iv(aes_xts); aes_xts->iv_set = 0; if (aes_xts->aes_key1 != NULL) zpc_aes_key_free(&aes_xts->aes_key1); if (aes_xts->aes_key2 != NULL) zpc_aes_key_free(&aes_xts->aes_key2); aes_xts->key_set = 0; aes_xts->fc = 0; } static void __aes_xts_reset_iv(struct zpc_aes_xts *aes_xts) { assert(aes_xts != NULL); if (aes_xts->key_set == 1) { assert(aes_xts->aes_key1 != NULL); assert(aes_xts->aes_key2 != NULL); memset(aes_xts->param_km + AES_XTS_KM_XTSPARAM(aes_xts->aes_key1->keysize), 0, 1 * 16); /* zero i, j, t, xtsparam */ memset(aes_xts->param_pcc + AES_XTS_PCC_I(aes_xts->aes_key2->keysize), 0, 4 * 16); } aes_xts->iv_set = 0; } libzpc-1.3.0/src/aes_xts_local.h000066400000000000000000000022441475140344100165630ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef AES_XTS_LOCAL_H # define AES_XTS_LOCAL_H # include "zpc/aes_key.h" # include "misc.h" # include "cpacf.h" /* * Internal aes_xts interface. */ /* 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_J(size) AES_XTS_PROTKEYLEN(size) + 1 * 16 # define AES_XTS_PCC_T(size) AES_XTS_PROTKEYLEN(size) + 2 * 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 struct zpc_aes_xts { u8 param_km[sizeof(struct cpacf_km_xts_aes_256_param)]; u8 param_pcc[sizeof(struct cpacf_pcc_xts_aes_256_param)]; struct zpc_aes_key *aes_key1; struct zpc_aes_key *aes_key2; unsigned int fc; int key_set; int iv_set; }; #endif libzpc-1.3.0/src/cpacf.h000066400000000000000000000276561475140344100150350ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef CPACF_H # define CPACF_H # include "misc.h" # define CPACF_M 0x80 /* Modifier bit */ /* KM */ /* Function codes */ # define CPACF_KM_QUERY 0 # define CPACF_KM_ENCRYPTED_AES_128 26 # define CPACF_KM_ENCRYPTED_AES_192 27 # define CPACF_KM_ENCRYPTED_AES_256 28 # define CPACF_KM_XTS_ENCRYPTED_AES_128 58 # define CPACF_KM_XTS_ENCRYPTED_AES_256 60 struct cpacf_km_aes_param { u8 protkey[64]; /* WKa(K)|WKaVP */ }; struct cpacf_km_xts_aes_128_param { u8 protkey[48]; /* WKa(K)|WKaVP */ u8 xtsparam[16]; }; struct cpacf_km_xts_aes_256_param { u8 protkey[64]; /* WKa(K)|WKaVP */ u8 xtsparam[16]; }; static inline int cpacf_km(unsigned long fc, void *param, u8 * out, const u8 * in, unsigned long inlen) { /* *INDENT-OFF* */ register unsigned long r0 __asm__("0") = (unsigned long) fc; register unsigned long r1 __asm__("1") = (unsigned long) param; register unsigned long r2 __asm__("2") = (unsigned long) in; register unsigned long r3 __asm__("3") = (unsigned long) inlen; register unsigned long r4 __asm__("4") = (unsigned long) out; u8 cc; __asm__ volatile( "0: .insn rre,%[opc] << 16,%[out],%[in]\n" " brc 1,0b\n" /* handle partial completion */ " ipm %[cc]\n" " srl %[cc],28\n" : [in] "+a" (r2), [inlen] "+d" (r3), [out] "+a" (r4), [cc] "=d" (cc) : [fc] "d" (r0), [param] "a" (r1), [opc] "i" (0xb92e) : "cc", "memory" ); /* *INDENT-ON* */ return cc; } /* KMC */ /* Function codes */ # define CPACF_KMC_QUERY 0 # define CPACF_KMC_ENCRYPTED_AES_128 26 # define CPACF_KMC_ENCRYPTED_AES_192 27 # define CPACF_KMC_ENCRYPTED_AES_256 28 struct cpacf_kmc_aes_param { u8 cv[16]; u8 protkey[64]; /* WKa(K)|WKaVP */ }; static inline int cpacf_kmc(unsigned long fc, void *param, u8 * out, const u8 * in, long inlen) { /* *INDENT-OFF* */ register unsigned long r0 __asm__("0") = (unsigned long) fc; register unsigned long r1 __asm__("1") = (unsigned long) param; register unsigned long r2 __asm__("2") = (unsigned long) in; register unsigned long r3 __asm__("3") = (unsigned long) inlen; register unsigned long r4 __asm__("4") = (unsigned long) out; u8 cc; __asm__ volatile( "0: .insn rre,%[opc] << 16,%[out],%[in]\n" " brc 1,0b\n" /* handle partial completion */ " ipm %[cc]\n" " srl %[cc],28\n" : [in] "+a" (r2), [inlen] "+d" (r3), [out] "+a" (r4), [cc] "=d" (cc) : [fc] "d" (r0), [param] "a" (r1), [opc] "i" (0xb92f) : "cc", "memory" ); /* *INDENT-ON* */ return cc; } /* KMAC */ /* Function codes */ # define CPACF_KMAC_QUERY 0 # define CPACF_KMAC_ENCRYPTED_AES_128 26 # define CPACF_KMAC_ENCRYPTED_AES_192 27 # define CPACF_KMAC_ENCRYPTED_AES_256 28 struct cpacf_kmac_aes_param { u8 icv[16]; u8 protkey[64]; /* WKa(K)|WKaVP */ }; static inline int cpacf_kmac(unsigned long fc, void *param, const u8 * in, unsigned long inlen) { /* *INDENT-OFF* */ register unsigned long r0 __asm__("0") = (unsigned long)fc; register unsigned long r1 __asm__("1") = (unsigned long)param; register unsigned long r2 __asm__("2") = (unsigned long)in; register unsigned long r3 __asm__("3") = (unsigned long)inlen; u8 cc; __asm__ volatile( "0: .insn rre,%[opc] << 16,0,%[in]\n" " brc 1,0b\n" /* handle partial completion */ " ipm %[cc]\n" " srl %[cc],28\n" : [in] "+a" (r2), [inlen] "+d" (r3), [cc] "=d" (cc) : [fc] "d" (r0), [param] "a" (r1), [opc] "i" (0xb91e) : "cc", "memory" ); /* *INDENT-ON* */ return cc; } /* PCC */ /* Function codes */ # define CPACF_PCC_QUERY 0 # define CPACF_PCC_CMAC_ENCRYPTED_AES_128 26 # define CPACF_PCC_CMAC_ENCRYPTED_AES_192 27 # define CPACF_PCC_CMAC_ENCRYPTED_AES_256 28 # define CPACF_PCC_XTS_ENCRYPTED_AES_128 58 # define CPACF_PCC_XTS_ENCRYPTED_AES_256 60 struct cpacf_pcc_xts_aes_128_param { u8 protkey[48]; /* WKa(K)|WKaVP */ u8 i[16]; u8 j[16]; u8 t[16]; u8 xtsparams[16]; }; struct cpacf_pcc_xts_aes_256_param { u8 protkey[64]; /* WKa(K)|WKaVP */ u8 i[16]; u8 j[16]; u8 t[16]; u8 xtsparams[16]; }; struct cpacf_pcc_cmac_aes_param { u8 ml; u8 reserved[7]; u8 message[16]; u8 icv[16]; u8 protkey[64]; /* WKa(K)|WKaVP */ }; /* PCC (perform cryptographuc computation) */ static inline int cpacf_pcc(unsigned long fc, void *param) { register unsigned long r0 __asm__("0") = (unsigned long)fc; register unsigned long r1 __asm__("1") = (unsigned long)param; u8 cc; /* *INDENT-OFF* */ __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) : [fc] "d" (r0), [param] "a" (r1), [opc] "i" (0xb92c) : "cc", "memory" ); /* *INDENT-ON* */ return cc; } /* KMA */ /* Function codes */ # define CPACF_KMA_QUERY 0 # define CPACF_KMA_GCM_ENCRYPTED_AES_128 26 # define CPACF_KMA_GCM_ENCRYPTED_AES_192 27 # define CPACF_KMA_GCM_ENCRYPTED_AES_256 28 /* Function code flags */ # define CPACF_KMA_LPC 0x100/* Last-Plaintext/Ciphertext */ # define CPACF_KMA_LAAD 0x200/* Last-AAD */ # define CPACF_KMA_HS 0x400/* Hash-subkey Supplied */ struct cpacf_kma_gcm_aes_param { u8 reserved[12]; u32 cv; u8 t[16]; u8 h[16]; u64 taadl; u64 tpcl; u8 j0[16]; u8 protkey[64]; /* WKa(K)|WKaVP */ }; /* KMA (cipher message with authentication) */ static inline int cpacf_kma(unsigned long fc, void *param, u8 * out, const u8 * aad, unsigned long aadlen, const u8 * in, unsigned long inlen) { /* *INDENT-OFF* */ register unsigned long r0 __asm__("0") = (unsigned long)fc; register unsigned long r1 __asm__("1") = (unsigned long)param; register unsigned long r2 __asm__("2") = (unsigned long)in; register unsigned long r3 __asm__("3") = (unsigned long)inlen; register unsigned long r4 __asm__("4") = (unsigned long)aad; register unsigned long r5 __asm__("5") = (unsigned long)aadlen; register unsigned long r6 __asm__("6") = (unsigned long)out; u8 cc; __asm__ volatile( "0: .insn rrf,%[opc]<<16,%[out],%[in],%[aad],0\n" " brc 1,0b\n" /* partial completion */ " ipm %[cc]\n" " srl %[cc],28\n" : [out] "+a" (r6), [cc] "=d" (cc), [in] "+a" (r2), [inlen] "+d" (r3), [aad] "+a" (r4), [aadlen] "+d" (r5) : [fc] "d" (r0), [param] "a" (r1), [opc] "i" (0xb929) : "cc", "memory" ); /* *INDENT-ON* */ return cc; } /* KDSA */ /* Function codes */ #define CPACF_KDSA_QUERY 0 #define CPACF_KDSA_ECDSA_VERIFY_ECP256 1 #define CPACF_KDSA_ECDSA_VERIFY_ECP384 2 #define CPACF_KDSA_ECDSA_VERIFY_ECP521 3 #define CPACF_KDSA_EDDSA_VERIFY_ED25519 32 #define CPACF_KDSA_EDDSA_VERIFY_ED448 36 #define CPACF_KDSA_ENCRYPTED_ECDSA_SIGN_P256 17 #define CPACF_KDSA_ENCRYPTED_ECDSA_SIGN_P384 18 #define CPACF_KDSA_ENCRYPTED_ECDSA_SIGN_P521 19 #define CPACF_KDSA_ENCRYPTED_EDDSA_SIGN_ED25519 48 #define CPACF_KDSA_ENCRYPTED_EDDSA_SIGN_ED448 52 /* Parameter blocks */ typedef struct cpacf_ecp256_sign_param { unsigned char sig_r[32]; unsigned char sig_s[32]; unsigned char hash[32]; unsigned char prot[32]; unsigned char rand[32]; unsigned char wkvp[32]; unsigned short c; } cpacf_ecp256_sign_param_t; typedef struct cpacf_ecp256_verify_param { unsigned char sig_r[32]; unsigned char sig_s[32]; unsigned char hash[32]; unsigned char pub_x[32]; unsigned char pub_y[32]; } cpacf_ecp256_verify_param_t; typedef struct cpacf_ecp384_sign_param { unsigned char sig_r[48]; unsigned char sig_s[48]; unsigned char hash[48]; unsigned char prot[48]; unsigned char rand[48]; unsigned char wkvp[32]; unsigned short c; } cpacf_ecp384_sign_param_t; typedef struct cpacf_ecp384_verify_param { unsigned char sig_r[48]; unsigned char sig_s[48]; unsigned char hash[48]; unsigned char pub_x[48]; unsigned char pub_y[48]; } cpacf_ecp384_verify_param_t; typedef struct cpacf_ecp521_sign_param { unsigned char sig_r[80]; unsigned char sig_s[80]; unsigned char hash[80]; unsigned char prot[80]; unsigned char rand[80]; unsigned char wkvp[32]; unsigned short c; } cpacf_ecp521_sign_param_t; typedef struct cpacf_ecp521_verify_param { unsigned char sig_r[80]; unsigned char sig_s[80]; unsigned char hash[80]; unsigned char pub_x[80]; unsigned char pub_y[80]; } cpacf_ecp521_verify_param_t; typedef struct cpacf_ed25519_sign_param { unsigned char sig_r[32]; unsigned char sig_s[32]; unsigned char prot[32]; unsigned char wkvp[32]; unsigned char res[16]; unsigned short c; } cpacf_ed25519_sign_param_t; typedef struct cpacf_ed25519_verify_param { unsigned char sig_r[32]; unsigned char sig_s[32]; unsigned char pub[32]; } cpacf_ed25519_verify_param_t; typedef struct cpacf_ed448_sign_param { unsigned char sig_r[64]; unsigned char sig_s[64]; unsigned char prot[64]; unsigned char wkvp[32]; unsigned char res[16]; unsigned short c; } cpacf_ed448_sign_param_t; typedef struct cpacf_ed448_verify_param { unsigned char sig_r[64]; unsigned char sig_s[64]; unsigned char pub[64]; } cpacf_ed448_verify_param_t; /** * cpacf_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 inline int cpacf_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; } 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"); } #endif libzpc-1.3.0/src/debug.h000066400000000000000000000023331475140344100150300ustar00rootroot00000000000000 /* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef DEBUG_H # define DEBUG_H # include "globals.h" # include # include # include # include # include # include # include "misc.h" # define __FILENAME__ \ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) # define DEBUG(...) \ do { \ if (debug) { \ int __rc; \ \ UNUSED(__rc); \ \ __rc = pthread_mutex_lock(&debuglock); \ assert(__rc == 0); \ \ fprintf(stderr, "libzpc %d.%d.%d: pid %llu: tid %llu: %s: %s:%d: ", \ ZPC_VERSION_MAJOR, ZPC_VERSION_MINOR, ZPC_VERSION_PATCH, \ (unsigned long long)getpid(), \ (unsigned long long)syscall(SYS_gettid), \ __func__, __FILENAME__, __LINE__); \ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, "\n"); \ \ __rc = pthread_mutex_unlock(&debuglock); \ assert(__rc == 0); \ } \ } while (0) #endif libzpc-1.3.0/src/ecc_key.c000066400000000000000000001231371475140344100153450ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include "zpc/ecc_key.h" #include "zpc/error.h" #include "ecc_key_local.h" #include "cpacf.h" #include "globals.h" #include "debug.h" #include "misc.h" #include "zkey/pkey.h" #include #include #include #include #include #include #include extern const size_t curve2publen[]; extern const size_t curve2privlen[]; extern const size_t curve2puboffset[]; extern const size_t curve2macedspkilen[]; extern const size_t curve2rawspkilen[]; extern const u32 curve2pkey_keytype[]; const u16 curve2pvsecret_type[] = { ZPC_EC_SECRET_ECDSA_P256, ZPC_EC_SECRET_ECDSA_P384, ZPC_EC_SECRET_ECDSA_P521, ZPC_EC_SECRET_EDDSA_ED25519, ZPC_EC_SECRET_EDDSA_ED448, }; static void __ec_key_reset(struct zpc_ec_key *); static int ec_key_check_ep11_spki(const struct zpc_ec_key *ec_key, const unsigned char *spki, unsigned int spki_len); static void ec_key_use_maced_spki_from_buf(struct zpc_ec_key *ec_key, const unsigned char *spki, unsigned int spki_len); static int ec_key_use_raw_spki_from_buf(struct zpc_ec_key *ec_key, const unsigned char *spki, unsigned int spki_len); static int ec_key_spki_has_valid_mkvp(const struct zpc_ec_key *ec_key, const unsigned char *spki, unsigned int spki_len); static int ec_key_blob_has_valid_mkvp(struct zpc_ec_key *ec_key, const unsigned char *buf); static int ec_key_blob_is_pkey_extractable(struct zpc_ec_key *ec_key, const unsigned char *buf); static int ec_key_apqns_have_valid_version(struct zpc_ec_key *ec_key); int ec_key_pvsec2prot(struct zpc_ec_key *ec_key); int ec_key_blob_is_valid_pvsecret_id(struct zpc_ec_key *ec_key, const unsigned char *id); int zpc_ec_key_alloc(struct zpc_ec_key **ec_key) { pthread_mutexattr_t attr; struct zpc_ec_key *new_ec_key = NULL; int rc, rv, attr_init = 0; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (ec_key == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } new_ec_key = calloc(1, sizeof(*new_ec_key)); if (new_ec_key == NULL) { rc = ZPC_ERROR_MALLOC; goto ret; } rc = pthread_mutexattr_init(&attr); if (rc) { rc = ZPC_ERROR_MALLOC; goto ret; } attr_init = 1; rv = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); assert(rv == 0); rc = pthread_mutex_init(&new_ec_key->lock, &attr); if (rc) { rc = ZPC_ERROR_INITLOCK; goto ret; } new_ec_key->refcount = 1; DEBUG("ec key at %p: refcount %llu", new_ec_key, new_ec_key->refcount); *ec_key = new_ec_key; rc = 0; ret: if (attr_init == 1) { rv = pthread_mutexattr_destroy(&attr); assert(rv == 0); } if (rc) free(new_ec_key); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_ec_key_set_curve(struct zpc_ec_key *ec_key, zpc_ec_curve_t curve) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (ec_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } switch (curve) { case ZPC_EC_CURVE_P256: /* fall-through */ case ZPC_EC_CURVE_P384: /* fall-through */ case ZPC_EC_CURVE_P521: case ZPC_EC_CURVE_ED25519: case ZPC_EC_CURVE_ED448: break; default: rc = ZPC_ERROR_EC_INVALID_CURVE; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&ec_key->lock); assert(rv == 0); if (ec_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } if (ec_key->curve_set == 1 && ec_key->curve != curve) { /* Unset key if it does not match the new EC curve. */ DEBUG("ec key at %p: key unset", ec_key); memset(&ec_key->cur, 0, sizeof(ec_key->cur)); memset(&ec_key->old, 0, sizeof(ec_key->old)); ec_key->curve_set = 0; } DEBUG("ec key at %p: curve set to %d", ec_key, curve); ec_key->curve = curve; ec_key->curve_set = 1; rc = 0; ret: rv = pthread_mutex_unlock(&ec_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_ec_key_set_type(struct zpc_ec_key *ec_key, int type) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (ec_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } switch (type) { case ZPC_EC_KEY_TYPE_CCA: /* fall-through */ case ZPC_EC_KEY_TYPE_EP11: case ZPC_EC_KEY_TYPE_PVSECRET: break; default: rc = ZPC_ERROR_KEYTYPE; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!swcaps.ecdsa_cca && type == ZPC_EC_KEY_TYPE_CCA) return ZPC_ERROR_CCA_HOST_LIB_NOT_AVAILABLE; else if (!swcaps.ecdsa_ep11 && type == ZPC_EC_KEY_TYPE_EP11) return ZPC_ERROR_EP11_HOST_LIB_NOT_AVAILABLE; else if (!swcaps.uv_pvsecrets && type == ZPC_EC_KEY_TYPE_PVSECRET) return ZPC_ERROR_UV_PVSECRETS_NOT_AVAILABLE; rv = pthread_mutex_lock(&ec_key->lock); assert(rv == 0); if (ec_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } if (ec_key->type_set == 1 && ec_key->type != type && ec_key->mkvp_set == 1) { /* Update mkvp-based apqn choices in case of type change. */ DEBUG("ec key at %p: update apqns to match type %d", ec_key, type); free(ec_key->apqns); ec_key->apqns = NULL; ec_key->napqns = 0; ec_key->apqns_set = 0; rc = alloc_apqns_from_mkvp(pkeyfd, &(ec_key->apqns), &(ec_key->napqns), ec_key->mkvp, type); if (rc != 0) goto ret; DEBUG("ec key at %p: %lu apqns set", ec_key, ec_key->napqns); ec_key->apqns_set = 1; } DEBUG("ec key at %p: type set to %d", ec_key, type); ec_key->type = type; ec_key->type_set = 1; rc = 0; ret: rv = pthread_mutex_unlock(&ec_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_ec_key_set_flags(struct zpc_ec_key *ec_key, unsigned int flags) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (ec_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&ec_key->lock); assert(rv == 0); if (ec_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } DEBUG("ec key at %p: flags set to %u", ec_key, flags); ec_key->flags = flags; ec_key->flags_set = 1; rc = 0; ret: rv = pthread_mutex_unlock(&ec_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } /* * Associate ec_key to all apqns of the given mkvp. */ int zpc_ec_key_set_mkvp(struct zpc_ec_key *ec_key, const char *mkvp) { u8 mkvpbuf[MAX_MKVPLEN]; size_t mkvpbuflen; int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (ec_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!swcaps.ecdsa_cca && ec_key->type == ZPC_EC_KEY_TYPE_CCA) return ZPC_ERROR_CCA_HOST_LIB_NOT_AVAILABLE; else if (!swcaps.ecdsa_ep11 && ec_key->type == ZPC_EC_KEY_TYPE_EP11) return ZPC_ERROR_EP11_HOST_LIB_NOT_AVAILABLE; rv = pthread_mutex_lock(&ec_key->lock); assert(rv == 0); if (ec_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } if (mkvp == NULL) { DEBUG("ec key at %p: apqns unset", ec_key); free(ec_key->apqns); ec_key->apqns = NULL; ec_key->napqns = 0; ec_key->apqns_set = 0; rc = 0; goto ret; } mkvpbuflen = sizeof(mkvpbuf); if (hexstr2buf(mkvpbuf, &mkvpbuflen, mkvp)) { rc = ZPC_ERROR_PARSE; goto ret; } if (mkvpbuflen != 8 && mkvpbuflen != 16 && mkvpbuflen != 32) { rc = ZPC_ERROR_MKVPLEN; goto ret; } if (ec_key->type_set != 1) { rc = ZPC_ERROR_KEYTYPENOTSET; goto ret; } DEBUG("ec key at %p: apqns unset", ec_key); free(ec_key->apqns); ec_key->apqns = NULL; ec_key->napqns = 0; ec_key->apqns_set = 0; if (ec_key->type == ZPC_EC_KEY_TYPE_PVSECRET) { rc = 0; /* function has no effect */ goto ret; } rc = alloc_apqns_from_mkvp(pkeyfd, &(ec_key->apqns), &(ec_key->napqns), mkvpbuf, ec_key->type); if (rc != 0) goto ret; DEBUG("ec key at %p: mkvp and %lu apqns set", ec_key, ec_key->napqns); memcpy(ec_key->mkvp, mkvpbuf, mkvpbuflen); ec_key->apqns_set = 1; ec_key->mkvp_set = 1; /* If the key already has a secure key set, its mkvp must match */ if (ec_key->cur.seclen > 0 && !ec_key_blob_has_valid_mkvp(ec_key, ec_key->cur.sec)) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } rc = 0; ret: rv = pthread_mutex_unlock(&ec_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } /* * Associate ec_key to a list NULL terminated list of apqns. */ int zpc_ec_key_set_apqns(struct zpc_ec_key *ec_key, const char *apqns[]) { unsigned int card, domain; size_t i, napqns; int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (ec_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&ec_key->lock); assert(rv == 0); if (apqns == NULL) { DEBUG("ec key at %p: apqns unset", ec_key); free(ec_key->apqns); ec_key->apqns = NULL; ec_key->napqns = 0; ec_key->apqns_set = 0; rc = 0; goto ret; } if (ec_key->type == ZPC_EC_KEY_TYPE_PVSECRET) { rc = 0; /* function has no effect */ goto ret; } for (napqns = 0; apqns[napqns] != NULL; napqns++); if (ec_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } DEBUG("ec key at %p: apqns unset", ec_key); free(ec_key->apqns); ec_key->apqns = NULL; ec_key->napqns = 0; ec_key->apqns_set = 0; DEBUG("ec key at %p: mkvp unset", ec_key); memset(ec_key->mkvp, 0, sizeof(ec_key->mkvp)); ec_key->mkvplen = 0; ec_key->mkvp_set = 0; if (napqns == 0) { rc = 0; /* nothing to do */ goto ret; } ec_key->apqns = calloc(napqns, sizeof(*(ec_key->apqns))); if (ec_key->apqns == NULL) return ZPC_ERROR_MALLOC; for (i = 0; i < napqns; i++) { rc = sscanf(apqns[i], " %x.%x ", &card, &domain); if (rc != 2) { rc = ZPC_ERROR_PARSE; goto ret; } ec_key->apqns[i].card = card; ec_key->apqns[i].domain = domain; } DEBUG("ec key at %p: %lu apqns set", ec_key, ec_key->napqns); ec_key->napqns = napqns; ec_key->apqns_set = 1; /* If the key already has a secure key set, its mkvp must match */ if (ec_key->cur.seclen > 0 && !ec_key_blob_has_valid_mkvp(ec_key, ec_key->cur.sec)) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } /* All APQNs must fulfill the hardware requirements for ECDSA */ if (!ec_key_apqns_have_valid_version(ec_key)) { rc = ZPC_ERROR_APQNS_INVALID_VERSION; goto ret; } rc = 0; ret: if (rc != 0) { free(ec_key->apqns); ec_key->apqns = NULL; ec_key->napqns = 0; } rv = pthread_mutex_unlock(&ec_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_ec_key_export(struct zpc_ec_key *ec_key, unsigned char *buf, unsigned int *buflen) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (ec_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (buflen == NULL) { rc = ZPC_ERROR_ARG3NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&ec_key->lock); assert(rv == 0); rc = ec_key_check(ec_key); if (rc) goto ret; if (buf == NULL) { *buflen = ec_key->cur.seclen; if (ec_key->pubkey_set) *buflen += ec_key->pub.spkilen; rc = 0; goto ret; } if (ec_key->pubkey_set && *buflen < ec_key->cur.seclen + ec_key->pub.spkilen) { *buflen = ec_key->cur.seclen + ec_key->pub.spkilen; rc = ZPC_ERROR_SMALLOUTBUF; goto ret; } if (!ec_key->pubkey_set && *buflen < ec_key->cur.seclen) { *buflen = ec_key->cur.seclen; rc = ZPC_ERROR_SMALLOUTBUF; goto ret; } *buflen = ec_key->cur.seclen; memcpy(buf, ec_key->cur.sec, *buflen); if (ec_key->pubkey_set) { memcpy(buf + *buflen, ec_key->pub.spki, ec_key->pub.spkilen); *buflen += ec_key->pub.spkilen; } rc = 0; ret: rv = pthread_mutex_unlock(&ec_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_ec_key_export_public(struct zpc_ec_key *ec_key, unsigned char *buf, unsigned int *buflen) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (ec_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (buflen == NULL) { rc = ZPC_ERROR_ARG3NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&ec_key->lock); assert(rv == 0); if (!ec_key->pubkey_set) { rc = ZPC_ERROR_EC_PUBKEY_NOTSET; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); goto ret; } if (buf == NULL) { *buflen = ec_key->pub.publen; rc = 0; goto ret; } if (*buflen < ec_key->pub.publen) { *buflen = ec_key->pub.publen; rc = ZPC_ERROR_SMALLOUTBUF; goto ret; } *buflen = ec_key->pub.publen; memcpy(buf, ec_key->pub.pubkey, *buflen); rc = 0; ret: rv = pthread_mutex_unlock(&ec_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_ec_key_import(struct zpc_ec_key *ec_key, const unsigned char *buf, unsigned int buflen) { target_t target; int rc, rv, seclen; size_t i, trailing_spki_len = 0; UNUSED(rv); if (pkeyfd < 0) { return ZPC_ERROR_DEVPKEY; } if (ec_key == NULL) { return ZPC_ERROR_ARG1NULL; } if (buf == NULL) { return ZPC_ERROR_ARG2NULL; } rv = pthread_mutex_lock(&ec_key->lock); assert(rv == 0); if (ec_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } if (ec_key->type != ZPC_EC_KEY_TYPE_PVSECRET) { if (buflen < MIN_EC_BLOB_SIZE || buflen > MAX_EC_BLOB_SIZE) { rc = ZPC_ERROR_ARG3RANGE; goto ret; } } else { if (buflen != UV_SECRET_ID_LEN) { rc = ZPC_ERROR_ARG3RANGE; goto ret; } } if (ec_key->curve_set != 1) { rc = ZPC_ERROR_EC_CURVE_NOTSET; goto ret; } if (ec_key->type_set != 1) { rc = ZPC_ERROR_KEYTYPENOTSET; goto ret; } if (ec_key->type == ZPC_EC_KEY_TYPE_CCA && !is_cca_ec_key(buf, buflen)) { rc = ZPC_ERROR_EC_NO_CCA_SECUREKEY_TOKEN; goto ret; } if (ec_key->type == ZPC_EC_KEY_TYPE_EP11 && !is_ep11_ec_key_with_header(buf, buflen)) { rc = ZPC_ERROR_EC_NO_EP11_SECUREKEY_TOKEN; goto ret; } if (ec_key->type != ZPC_EC_KEY_TYPE_PVSECRET) { if (!ec_key_blob_has_valid_mkvp(ec_key, buf)) { rc = ZPC_ERROR_WKVPMISMATCH; goto ret; } if (!ec_key_blob_is_pkey_extractable(ec_key, buf)) { rc = ZPC_ERROR_BLOB_NOT_PKEY_EXTRACTABLE; goto ret; } } if (ec_key->type == ZPC_EC_KEY_TYPE_PVSECRET) { if (ec_key_blob_is_valid_pvsecret_id(ec_key, buf) != 0) { rc = ZPC_ERROR_PVSECRET_ID_NOT_FOUND_IN_UV; goto ret; } } /* In case of ep11, the imported buffer may contain the actual secure key * blob concatenated with a public key spki. */ if (ec_key->type == ZPC_EC_KEY_TYPE_EP11) trailing_spki_len = buflen - ep11_get_raw_blob_length(buf); /* Set (secure) private key. Host lib not needed for this. */ seclen = buflen - trailing_spki_len; memset(ec_key->cur.sec, 0, sizeof(ec_key->cur.sec)); memcpy(ec_key->cur.sec, buf, seclen); ec_key->cur.seclen = seclen; ec_key->key_set = 1; /* Extract and set public key. For this we need the related host lib. If * the host lib is not available, only the secure key is available in * this key object. */ if (ec_key->type == ZPC_EC_KEY_TYPE_CCA) { if (!swcaps.ecdsa_cca) { rc = 0; goto ret; } ec_key->pubkey_set = 1; rv = pthread_mutex_lock(&ccalock); assert(rv == 0); rc = ec_key_extract_public_cca(&cca, (unsigned char *)&ec_key->cur.sec, ec_key->cur.seclen, (unsigned char *)&ec_key->pub.pubkey, &ec_key->pub.publen, true); rv = pthread_mutex_unlock(&ccalock); assert(rv == 0); if (rc != 0 || ec_key->pub.publen == 0) ec_key->pubkey_set = 0; } else if (ec_key->type == ZPC_EC_KEY_TYPE_EP11){ if (!swcaps.ecdsa_ep11) { rc = 0; goto ret; } ec_key->pubkey_set = 1; rv = pthread_mutex_lock(&ep11lock); assert(rv == 0); for (i = 0; i < ec_key->napqns; i++) { rc = get_ep11_target_for_apqn(&ep11, ec_key->apqns[i].card, ec_key->apqns[i].domain, &target, true); if (rc) continue; rc = ec_key_extract_public_ep11(&ep11, ec_key->curve, (unsigned char *)&ec_key->cur.sec, ec_key->cur.seclen, (unsigned char *)&ec_key->pub.pubkey, &ec_key->pub.publen, (unsigned char *)&ec_key->pub.spki, &ec_key->pub.spkilen, target); free_ep11_target_for_apqn(&ep11, target); if (rc == 0) break; } rv = pthread_mutex_unlock(&ep11lock); assert(rv == 0); if (rc != 0 || ec_key->pub.publen == 0) ec_key->pubkey_set = 0; } else { /* PVSECRET: not possible to calculate public key from secret */ ec_key->pubkey_set = 0; rc = 0; goto ret; } /* At this point the secure key blob is imported. * - If the blob itself contains a public key, it's now extracted into the * key struct, but only if this key obj has apqns/mkvps. Otherwise we * could not extract the public key from the blob and the key obj has * no public key so far. * - If there is a public key SPKI appended to the blob, we parse it out * of the SPKI (which does not require apqns/mkvps). But we have no way * for checking the correctness of the public key. * - If the public key could be extracted from the blob and SPKI, we have * the public key given a second time. In this case we check if both * pubkeys match. */ if (ec_key->type == ZPC_EC_KEY_TYPE_EP11 && trailing_spki_len > 0) { const unsigned char *spki = buf + seclen; if (ec_key_check_ep11_spki(ec_key, spki, trailing_spki_len) == 0) { if (trailing_spki_len == curve2rawspkilen[ec_key->curve]) { rc = ec_key_use_raw_spki_from_buf(ec_key, spki, trailing_spki_len); if (rc != 0) goto ret; } else { ec_key_use_maced_spki_from_buf(ec_key, spki, trailing_spki_len); } } } rc = 0; ret: rv = pthread_mutex_unlock(&ec_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_ec_key_import_clear(struct zpc_ec_key *ec_key, const unsigned char *pubkey, unsigned int publen, const unsigned char *privkey, unsigned int privlen) { unsigned int flags; int rc, rv; size_t i; target_t target; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (ec_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!pubkey && !privkey) { rc = ZPC_ERROR_EC_NO_KEY_PARTS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (privkey && privlen > 0) { /* We only need host libs if we import the privkey. */ if (!swcaps.ecdsa_cca && ec_key->type == ZPC_EC_KEY_TYPE_CCA) return ZPC_ERROR_CCA_HOST_LIB_NOT_AVAILABLE; else if (!swcaps.ecdsa_ep11 && ec_key->type == ZPC_EC_KEY_TYPE_EP11) return ZPC_ERROR_EP11_HOST_LIB_NOT_AVAILABLE; } rv = pthread_mutex_lock(&ec_key->lock); assert(rv == 0); if (ec_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } if (ec_key->curve_set != 1) { rc = ZPC_ERROR_EC_CURVE_NOTSET; goto ret; } if (ec_key->type_set != 1) { rc = ZPC_ERROR_KEYTYPENOTSET; goto ret; } if (ec_key->type != ZPC_EC_KEY_TYPE_PVSECRET && ec_key->apqns_set != 1) { rc = ZPC_ERROR_APQNSNOTSET; goto ret; } flags = ec_key->flags_set == 1 ? ec_key->flags : 0; if (publen > 0 && publen != curve2publen[ec_key->curve]) { rc = ZPC_ERROR_EC_PUBKEY_LENGTH; goto ret; } if (privlen > 0 && privlen != curve2privlen[ec_key->curve]) { rc = ZPC_ERROR_EC_PRIVKEY_LENGTH; goto ret; } if (privkey && privlen > 0) { memset(&ec_key->cur, 0, sizeof(ec_key->cur)); memset(&ec_key->old, 0, sizeof(ec_key->old)); memset(&ec_key->prot, 0, sizeof(ec_key->prot)); ec_key->key_set = 0; rc = ec_key_clr2sec(ec_key, flags, pubkey, publen, privkey, privlen); if (rc) { goto ret; } rc = ec_key_clr2prot(ec_key, privkey, privlen); if (rc) { rc = ec_key_sec2prot(ec_key, EC_KEY_SEC_CUR); if (rc) { goto ret; } } DEBUG("ec key at %p: private/protected key set", ec_key); ec_key->key_set = 1; } if (pubkey && publen > 0) { memcpy(&ec_key->pub.pubkey, pubkey, publen); ec_key->pub.publen = publen; DEBUG("ec key at %p: public key set", ec_key); ec_key->pubkey_set = 1; } /* In case of ep11, create a MACed spki from the given raw public key and * add it to the key struct. */ if (ec_key->pubkey_set == 1 && ec_key->type == ZPC_EC_KEY_TYPE_EP11) { unsigned char temp[MAX_MACED_SPKI_SIZE]; unsigned int temp_len = sizeof(temp); rv = pthread_mutex_lock(&ep11lock); assert(rv == 0); for (i = 0; i < ec_key->napqns; i++) { rc = get_ep11_target_for_apqn(&ep11, ec_key->apqns[i].card, ec_key->apqns[i].domain, &target, true); if (rc) continue; ep11_make_spki(ec_key->curve, ec_key->pub.pubkey, ec_key->pub.publen, (unsigned char *)&temp, &temp_len); ec_key->pub.spkilen = sizeof(ec_key->pub.spki); rc = ep11_make_maced_spki(&ep11, temp, temp_len, ec_key->pub.spki, &ec_key->pub.spkilen, target); free_ep11_target_for_apqn(&ep11, target); if (rc == 0) break; } rv = pthread_mutex_unlock(&ep11lock); assert(rv == 0); } rc = 0; ret: if (rc != 0) memset(&ec_key->cur, 0, sizeof(ec_key->cur)); rv = pthread_mutex_unlock(&ec_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_ec_key_generate(struct zpc_ec_key *ec_key) { target_t target; unsigned int flags; int rc, rv; size_t i; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (ec_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!swcaps.ecdsa_cca && ec_key->type == ZPC_EC_KEY_TYPE_CCA) return ZPC_ERROR_CCA_HOST_LIB_NOT_AVAILABLE; else if (!swcaps.ecdsa_ep11 && ec_key->type == ZPC_EC_KEY_TYPE_EP11) return ZPC_ERROR_EP11_HOST_LIB_NOT_AVAILABLE; rv = pthread_mutex_lock(&ec_key->lock); assert(rv == 0); if (ec_key->refcount != 1) { rc = ZPC_ERROR_OBJINUSE; goto ret; } if (ec_key->type == ZPC_EC_KEY_TYPE_PVSECRET) { rc = ZPC_ERROR_KEYTYPE; goto ret; } if (ec_key->curve_set != 1) { rc = ZPC_ERROR_EC_CURVE_NOTSET; goto ret; } if (ec_key->apqns_set != 1) { /* EC keys cannot be generated without APQNs, because we do it via * the host libs. */ rc = ZPC_ERROR_APQNS_NOTSET; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); goto ret; } if (ec_key->type_set != 1) { rc = ZPC_ERROR_KEYTYPENOTSET; goto ret; } flags = ec_key->flags_set == 1 ? ec_key->flags : 0; memset(&ec_key->cur, 0, sizeof(ec_key->cur)); memset(&ec_key->old, 0, sizeof(ec_key->old)); ec_key->key_set = 0; ec_key->pubkey_set = 0; /* Generate secure EC key via host libs */ switch (ec_key->type) { case ZPC_EC_KEY_TYPE_CCA: rv = pthread_mutex_lock(&ccalock); assert(rv == 0); rc = ec_key_generate_cca(&cca, ec_key->curve, flags, (unsigned char *)&ec_key->cur.sec, &ec_key->cur.seclen, (unsigned char *)&ec_key->pub.pubkey, &ec_key->pub.publen, true); rv = pthread_mutex_unlock(&ccalock); assert(rv == 0); if (rc) goto ret; break; case ZPC_EC_KEY_TYPE_EP11: rv = pthread_mutex_lock(&ep11lock); assert(rv == 0); for (i = 0; i < ec_key->napqns; i++) { rc = get_ep11_target_for_apqn(&ep11, ec_key->apqns[i].card, ec_key->apqns[i].domain, &target, true); if (rc) continue; rc = ec_key_generate_ep11(&ep11, ec_key->curve, flags, (unsigned char *)&ec_key->cur.sec, &ec_key->cur.seclen, (unsigned char *)&ec_key->pub.pubkey, &ec_key->pub.publen, (unsigned char *)&ec_key->pub.spki, &ec_key->pub.spkilen, target); free_ep11_target_for_apqn(&ep11, target); if (rc == 0) break; } rv = pthread_mutex_unlock(&ep11lock); assert(rv == 0); break; default: rc = ZPC_ERROR_KEYTYPE; goto ret; } DEBUG("ec key at %p: privkey set to generated secure key", ec_key); DEBUG("ec key at %p: pubkey extracted from secure key token", ec_key); ec_key->key_set = 1; ec_key->pubkey_set = 1; /* Transform secure key into protected key */ rc = ec_key_sec2prot(ec_key, EC_KEY_SEC_CUR); if (rc) goto ret; DEBUG("ec key at %p: protkey created from secure key token", ec_key); rc = 0; ret: if (rc != 0) memset(&ec_key->cur, 0, sizeof(ec_key->cur)); rv = pthread_mutex_unlock(&ec_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_ec_key_reencipher(struct zpc_ec_key *ec_key, unsigned int method) { struct ec_key reenc; unsigned int seckeylen; target_t target; int rv, rc = ZPC_ERROR_APQNSNOTSET; size_t i; unsigned char temp[MAX_MACED_SPKI_SIZE]; unsigned int temp_len = sizeof(temp); UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (ec_key == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&ec_key->lock); assert(rv == 0); if (ec_key->key_set == 0) { rc = ZPC_ERROR_EC_PRIVKEY_NOTSET; goto ret; } if (ec_key->curve_set == 0) { rc = ZPC_ERROR_EC_CURVE_NOTSET; goto ret; } if (ec_key->type_set == 0) { rc = ZPC_ERROR_KEYTYPENOTSET; goto ret; } if (ec_key->type == ZPC_EC_KEY_TYPE_PVSECRET) { /* reencipher not applicable for pvsecrets */ rc = ZPC_ERROR_KEYTYPE; goto ret; } if (ec_key->apqns_set == 0 || ec_key->napqns == 0) { rc = ZPC_ERROR_APQNSNOTSET; goto ret; } memcpy(&reenc, &ec_key->cur, sizeof(reenc)); switch (ec_key->type) { case ZPC_EC_KEY_TYPE_CCA: seckeylen = ec_key->cur.seclen; rv = pthread_mutex_lock(&ccalock); assert(rv == 0); for (i = 0; i < ec_key->napqns; i++) { rc = select_cca_adapter(&cca, ec_key->apqns[i].card, ec_key->apqns[i].domain, true); if (rc) continue; rc = key_token_change(&cca, reenc.sec, seckeylen, method == ZPC_EC_KEY_REENCIPHER_OLD_TO_CURRENT ? METHOD_OLD_TO_CURRENT : METHOD_CURRENT_TO_NEW, true); if (rc == 0) break; } rv = pthread_mutex_unlock(&ccalock); assert(rv == 0); break; case ZPC_EC_KEY_TYPE_EP11: if (method != ZPC_EC_KEY_REENCIPHER_CURRENT_TO_NEW) { rc = ZPC_ERROR_NOTSUP; goto ret; } rv = pthread_mutex_lock(&ep11lock); assert(rv == 0); for (i = 0; i < ec_key->napqns; i++) { rc = get_ep11_target_for_apqn(&ep11, ec_key->apqns[i].card, ec_key->apqns[i].domain, &target, true); if (rc) continue; /* Note that the secure key is a TOKVER_EP11_ECC_WITH_HEADER and has a * 16-byte ep11kblob_header prepended before the actual secure key blob. * For reencipher we have to skip this prepended hdr and provide the * key blob directly. */ rc = reencipher_ep11_key(&ep11, target, ec_key->apqns[i].card, ec_key->apqns[i].domain, reenc.sec + sizeof(struct ep11kblob_header), ec_key->cur.seclen - sizeof(struct ep11kblob_header), true); rc += ep11_make_maced_spki(&ep11, (unsigned char *)&ec_key->pub.spki, curve2rawspkilen[ec_key->curve], temp, &temp_len, target); if (rc == 0) { memcpy(ec_key->pub.spki, temp, temp_len); ec_key->pub.spkilen = temp_len; } free_ep11_target_for_apqn(&ep11, target); if (rc == 0) break; } rv = pthread_mutex_unlock(&ep11lock); assert(rv == 0); break; default: rc = ZPC_ERROR_KEYTYPE; } if (rc) goto ret; memcpy(&ec_key->old, &ec_key->cur, sizeof(ec_key->old)); memcpy(&ec_key->cur, &reenc, sizeof(ec_key->cur)); rc = 0; ret: rv = pthread_mutex_unlock(&ec_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } void zpc_ec_key_free(struct zpc_ec_key **ec_key) { int rv, free_obj = 0; UNUSED(rv); if (ec_key == NULL) return; if (*ec_key == NULL) return; rv = pthread_mutex_lock(&(*ec_key)->lock); assert(rv == 0); if ((*ec_key)->refcount == 0) goto ret; (*ec_key)->refcount--; DEBUG("ec key at %p: refcount %llu", *ec_key, (*ec_key)->refcount); if ((*ec_key)->refcount == 0) { free_obj = 1; __ec_key_reset(*ec_key); } ret: rv = pthread_mutex_unlock(&(*ec_key)->lock); assert(rv == 0); if (free_obj == 1) { rv = pthread_mutex_destroy(&(*ec_key)->lock); assert(rv == 0); free(*ec_key); } *ec_key = NULL; DEBUG("return"); } /* * Reset everything that was set after allocation. * Caller must hold ec_key's wr lock. */ static void __ec_key_reset(struct zpc_ec_key *ec_key) { assert(ec_key != NULL); memset(&ec_key->cur, 0, sizeof(ec_key->cur)); memset(&ec_key->old, 0, sizeof(ec_key->old)); memset(&ec_key->prot, 0, sizeof(ec_key->prot)); memset(&ec_key->pub, 0, sizeof(ec_key->pub)); ec_key->key_set = 0; ec_key->pubkey_set = 0; ec_key->curve = 0; ec_key->curve_set = 0; ec_key->flags = 0; ec_key->flags_set = 0; ec_key->type = 0; ec_key->type_set = 0; memset(ec_key->mkvp, 0, sizeof(ec_key->mkvp)); ec_key->mkvplen = 0; ec_key->mkvp_set = 0; free(ec_key->apqns); ec_key->apqns = NULL; ec_key->napqns = 0; ec_key->apqns_set = 0; ec_key->refcount = 1; } u16 ecprotkeylen_from_pvsectype(u16 pvsectype) { switch (pvsectype) { case ZPC_EC_SECRET_ECDSA_P256: return 32 + 32; case ZPC_EC_SECRET_ECDSA_P384: return 48 + 32; case ZPC_EC_SECRET_ECDSA_P521: return 80 + 32; case ZPC_EC_SECRET_EDDSA_ED25519: return 32 + 32; case ZPC_EC_SECRET_EDDSA_ED448: return 64 + 32; default: break; } return 0; } void ec_key_make_uvrsecrettoken(struct zpc_ec_key *ec_key, const unsigned char *id, unsigned char *buf) { struct uvrsecrettoken *clrtok = (struct uvrsecrettoken *)buf; clrtok->version = TOKVER_UV_SECRET; clrtok->secret_type = curve2pvsecret_type[ec_key->curve]; clrtok->secret_len = ecprotkeylen_from_pvsectype(clrtok->secret_type); memcpy(clrtok->secret_id, id, UV_SECRET_ID_LEN); } /* * Verify that a given pvsecret ID is a valid ID on this system, i.e. an UV * secret exists with this ID and has the expected key length. */ int ec_key_blob_is_valid_pvsecret_id(struct zpc_ec_key *ec_key, const unsigned char *id) { struct pkey_verifykey2 io; unsigned char buf[sizeof(struct uvrsecrettoken)] = { 0, }; int rc; ec_key_make_uvrsecrettoken(ec_key, id, buf); memset(&io, 0, sizeof(io)); io.key = buf; io.keylen = sizeof(struct uvrsecrettoken); errno = 0; rc = ioctl(pkeyfd, PKEY_VERIFYKEY2, &io); if (rc != 0) { DEBUG("ec key at %p: PKEY_VERIFYKEY2 ioctl failed, errno = %d", ec_key, errno); return ZPC_ERROR_IOCTLVERIFYKEY2; } return 0; } /* * (Re)derive protected key from a retrievable secret ID. * Caller must hold aes_key's wr lock. */ int ec_key_pvsec2prot(struct zpc_ec_key *ec_key) { struct pkey_kblob2pkey3 io; unsigned char buf[sizeof(struct uvrsecrettoken)] = { 0, }; int rc; ec_key_make_uvrsecrettoken(ec_key, ec_key->cur.sec, buf); memset(&io, 0, sizeof(io)); io.key = buf; io.keylen = sizeof(struct uvrsecrettoken); io.pkeytype = ec_key->type; io.pkeylen = sizeof(ec_key->prot.protkey); io.pkey = (unsigned char *)&ec_key->prot.protkey; errno = 0; rc = ioctl(pkeyfd, PKEY_KBLOB2PROTK3, &io); if (rc != 0) { DEBUG("ec key at %p: PKEY_VERIFYKEY2 ioctl failed, errno = %d", ec_key, errno); return ZPC_ERROR_IOCTLBLOB2PROTK3; } return 0; } int ec_key_clr2sec(struct zpc_ec_key *ec_key, unsigned int flags, const unsigned char *pubkey, unsigned int publen, const unsigned char *privkey, unsigned int privlen) { target_t target; int rv, rc = ZPC_ERROR_APQNSNOTSET; size_t i; switch (ec_key->type) { case ZPC_EC_KEY_TYPE_CCA: rv = pthread_mutex_lock(&ccalock); assert(rv == 0); rc = ec_key_clr2sec_cca(&cca, ec_key->curve, flags, (unsigned char *)&ec_key->cur.sec, &ec_key->cur.seclen, pubkey, publen, privkey, privlen, true); rv = pthread_mutex_unlock(&ccalock); assert(rv == 0); if (rc != 0) rc = ZPC_ERROR_EC_KEY_PARTS_INCONSISTENT; break; case ZPC_EC_KEY_TYPE_EP11: rv = pthread_mutex_lock(&ep11lock); assert(rv == 0); for (i = 0; i < ec_key->napqns; i++) { rc = get_ep11_target_for_apqn(&ep11, ec_key->apqns[i].card, ec_key->apqns[i].domain, &target, true); if (rc) continue; rc = ec_key_clr2sec_ep11(&ep11, ec_key->curve, flags, (unsigned char *)&ec_key->cur.sec, &ec_key->cur.seclen, pubkey, publen, privkey, privlen, target); free_ep11_target_for_apqn(&ep11, target); if (rc == 0) break; } rv = pthread_mutex_unlock(&ep11lock); assert(rv == 0); if (rc != 0) rc = ZPC_ERROR_EC_KEY_PARTS_INCONSISTENT; break; default: rc = ZPC_ERROR_KEYTYPE; break; } return rc; } /* * (Re)derive protected key from a secure key. * Caller must hold ec_key's wr lock. */ int ec_key_sec2prot(struct zpc_ec_key *ec_key, enum ec_key_sec sec) { struct pkey_kblob2pkey3 io; struct ec_key *key = NULL; unsigned int keybuf_len; int rc, i; assert(sec == EC_KEY_SEC_OLD || sec == EC_KEY_SEC_CUR); if (sec == EC_KEY_SEC_CUR) key = &ec_key->cur; else if (sec == EC_KEY_SEC_OLD) key = &ec_key->old; assert(key != NULL); if (ec_key->type == ZPC_EC_KEY_TYPE_PVSECRET) return ec_key_pvsec2prot(ec_key); else if (ec_key->type == ZPC_EC_KEY_TYPE_EP11) keybuf_len = key->seclen + sizeof(struct ep11kblob_header); else keybuf_len = key->seclen; memset(&io, 0, sizeof(io)); io.key = key->sec; io.keylen = keybuf_len; io.apqns = ec_key->apqns; io.apqn_entries = ec_key->napqns; io.pkeytype = (ec_key->type == ZPC_EC_KEY_TYPE_CCA ? PKEY_TYPE_CCA_ECC : PKEY_TYPE_EP11_ECC); io.pkeylen = sizeof(ec_key->prot.protkey); io.pkey = (unsigned char *)&ec_key->prot.protkey; for (i = 0; i < 10; i++) { rc = ioctl(pkeyfd, PKEY_KBLOB2PROTK3, &io); if (rc == 0 || (errno != -EBUSY && errno != -EAGAIN)) break; sleep(1); } if (rc != 0) { return ZPC_ERROR_IOCTLBLOB2PROTK3; } return 0; } int ec_key_clr2prot(struct zpc_ec_key *ec_key, const unsigned char *privkey, unsigned int privlen) { struct pkey_kblob2pkey3 io; unsigned char buf[sizeof(struct clearkeytoken) + 80]; struct clearkeytoken *clrtok = (struct clearkeytoken *)&buf; int rc; memset(buf, 0, sizeof(buf)); clrtok->version = 0x02; clrtok->keytype = curve2pkey_keytype[ec_key->curve]; switch (clrtok->keytype) { case PKEY_KEYTYPE_ECC_P256: case PKEY_KEYTYPE_ECC_P384: case PKEY_KEYTYPE_ECC_ED25519: memcpy(clrtok->clearkey, privkey, privlen); clrtok->len = privlen; break; case PKEY_KEYTYPE_ECC_P521: memcpy(clrtok->clearkey + 80 - privlen, privkey, privlen); clrtok->len = 80; break; case PKEY_KEYTYPE_ECC_ED448: memcpy(clrtok->clearkey + 64 - privlen, privkey, privlen); clrtok->len = 64; break; default: /* should not occur */ return ZPC_ERROR_EC_INVALID_CURVE; } memset(&io, 0, sizeof(io)); io.key = buf; switch (clrtok->keytype) { case PKEY_KEYTYPE_ECC_P256: case PKEY_KEYTYPE_ECC_P384: case PKEY_KEYTYPE_ECC_ED25519: io.keylen = sizeof(struct clearkeytoken) + privlen; break; case PKEY_KEYTYPE_ECC_P521: io.keylen = sizeof(struct clearkeytoken) + 80; break; case PKEY_KEYTYPE_ECC_ED448: io.keylen = sizeof(struct clearkeytoken) + 64; break; default: /* should not occur */ return ZPC_ERROR_EC_INVALID_CURVE; } io.apqns = ec_key->apqns; io.apqn_entries = ec_key->napqns; io.pkeytype = (ec_key->type == ZPC_EC_KEY_TYPE_CCA ? PKEY_TYPE_CCA_ECC : PKEY_TYPE_EP11_ECC); io.pkeylen = sizeof(ec_key->prot.protkey); io.pkey = (unsigned char *)&ec_key->prot.protkey; rc = ioctl(pkeyfd, PKEY_KBLOB2PROTK3, &io); if (rc != 0) { return ZPC_ERROR_IOCTLBLOB2PROTK3; } return 0; } int ec_key_check(const struct zpc_ec_key *ec_key) { if (ec_key->key_set != 1 && ec_key->pubkey_set != 1) return ZPC_ERROR_EC_NO_KEY_PARTS; if (ec_key->curve_set != 1) return ZPC_ERROR_EC_CURVE_NOTSET; if (ec_key->type_set != 1) return ZPC_ERROR_KEYTYPENOTSET; return 0; } int ec_key_spki_valid_for_pubkey(const struct zpc_ec_key *ec_key, const unsigned char *spki) { if (ec_key->pubkey_set == 0) return 1; /* no pubkey given to check against */ if (memcmp(ec_key->pub.pubkey, spki + curve2puboffset[ec_key->curve], ec_key->pub.publen) == 0) return 1; return 0; } static int ec_key_check_ep11_spki(const struct zpc_ec_key *ec_key, const unsigned char *spki, unsigned int spki_len) { if (spki_len > curve2macedspkilen[ec_key->curve] && spki_len < curve2rawspkilen[ec_key->curve]) return ZPC_ERROR_EC_EP11_SPKI_INVALID_LENGTH; if (!ep11_spki_valid_for_curve(ec_key->curve, spki, spki_len)) return ZPC_ERROR_EC_EP11_SPKI_INVALID_CURVE; if (spki_len == curve2macedspkilen[ec_key->curve] && !ec_key_spki_valid_for_pubkey(ec_key, spki)) return ZPC_ERROR_EC_EP11_SPKI_INVALID_PUBKEY; if (spki_len == curve2macedspkilen[ec_key->curve] && !ec_key_spki_has_valid_mkvp(ec_key, spki, spki_len)) return ZPC_ERROR_EC_EP11_SPKI_INVALID_MKVP; return 0; } static void ec_key_use_maced_spki_from_buf(struct zpc_ec_key *ec_key, const unsigned char *spki, unsigned int spki_len) { memcpy(ec_key->pub.spki, spki, spki_len); ec_key->pub.spkilen = spki_len; memcpy(ec_key->pub.pubkey, spki + curve2puboffset[ec_key->curve], curve2publen[ec_key->curve]); ec_key->pub.publen = curve2publen[ec_key->curve]; ec_key->pubkey_set = 1; } static int ec_key_use_raw_spki_from_buf(struct zpc_ec_key *ec_key, const unsigned char *spki, unsigned int spki_len) { target_t target; int rc = -EIO, rv; size_t i; rv = pthread_mutex_lock(&ep11lock); assert(rv == 0); for (i = 0; i < ec_key->napqns; i++) { rc = get_ep11_target_for_apqn(&ep11, ec_key->apqns[i].card, ec_key->apqns[i].domain, &target, true); if (rc) continue; rc = ep11_make_maced_spki(&ep11, spki, spki_len, ec_key->pub.spki, &ec_key->pub.spkilen, target); free_ep11_target_for_apqn(&ep11, target); if (rc == 0) break; } if (rc == 0) { memcpy(ec_key->pub.pubkey, spki + curve2puboffset[ec_key->curve], curve2publen[ec_key->curve]); ec_key->pub.publen = curve2publen[ec_key->curve]; ec_key->pubkey_set = 1; } rv = pthread_mutex_unlock(&ep11lock); assert(rv == 0); return rc; } static int ec_key_spki_has_valid_mkvp(const struct zpc_ec_key *ec_key, const unsigned char *spki, unsigned int spki_len) { (void)spki_len; /* suppress unused parm compiler warning */ spki_mac_t *mac_part = (spki_mac_t *)(spki + curve2rawspkilen[ec_key->curve]); if (ec_key->mkvp_set == 0) return 1; /* cannot judge */ if (memcmp(ec_key->mkvp, mac_part->wk_id, 16) == 0) return 1; return 0; } static int ec_key_blob_has_valid_mkvp(struct zpc_ec_key *ec_key, const unsigned char *buf) { const unsigned char *mkvp; unsigned int mkvp_len; if (ec_key->mkvp_set == 0) return 1; /* cannot judge */ if (ec_key->type == ZPC_EC_KEY_TYPE_CCA) { mkvp = ((struct ccakeytoken *)buf)->mkvp; mkvp_len = MKVP_LEN_CCA; } else { /* Keys of type PKEY_TYPE_EP11_ECC have a ep11kblob_header prepended * before the actual key blob */ const unsigned char *buf2 = buf + sizeof(struct ep11kblob_header); mkvp = ((struct ep11keytoken *)buf2)->wkvp; mkvp_len = MKVP_LEN_EP11; } if (memcmp(ec_key->mkvp, mkvp, mkvp_len) == 0) return 1; return 0; } static int ec_key_blob_is_pkey_extractable(struct zpc_ec_key *ec_key, const unsigned char *buf) { if (ec_key->type == ZPC_EC_KEY_TYPE_CCA) { u8 keyusage = ((struct ccakeytoken *)buf)->keyusage; if (keyusage & CCA_XPRTCPAC) return 1; } else { /* Keys of type PKEY_TYPE_EP11_ECC have a ep11kblob_header prepended * before the actual key blob */ const unsigned char *buf2 = buf + sizeof(struct ep11kblob_header); u64 attr = ((struct ep11keytoken *)buf2)->attr; if (attr & XCP_BLOB_PROTKEY_EXTRACTABLE) return 1; } return 0; } static int file_fgets(const char *fname, char *buf, size_t buflen) { FILE *fp; char *end; int rc = CKR_OK; buf[0] = '\0'; fp = fopen(fname, "r"); if (fp == NULL) { DEBUG("Failed to open file '%s'\n", fname); return EIO; } if (fgets(buf, buflen, fp) == NULL) { DEBUG("Failed to read from file '%s'\n", fname); rc = EIO; goto out_fclose; } end = memchr(buf, '\n', buflen); if (end) *end = 0; else buf[buflen - 1] = 0; if (strlen(buf) == 0) rc = EIO; out_fclose: fclose(fp); return rc; } static int get_card_type(unsigned int adapter, unsigned int *type) { char fname[250]; char buf[250]; int rc; unsigned int hwtype, rawtype; sprintf(fname, "%scard%02x/type", SYSFS_DEVICES_AP, adapter); rc = file_fgets(fname, buf, sizeof(buf)); if (rc != 0) return rc; if (sscanf(buf, "CEX%uP", type) != 1 && sscanf(buf, "CEX%uC", type) != 1) return EIO; sprintf(fname, "%scard%02x/hwtype", SYSFS_DEVICES_AP, adapter); rc = file_fgets(fname, buf, sizeof(buf)); if (rc != 0) return rc; if (sscanf(buf, "%u", &hwtype) != 1) return EIO; sprintf(fname, "%scard%02x/raw_hwtype", SYSFS_DEVICES_AP, adapter); rc = file_fgets(fname, buf, sizeof(buf)); if (rc != 0) return rc; if (sscanf(buf, "%u", &rawtype) != 1) return EIO; if (rawtype > hwtype) { DEBUG("%s adapter: %u hwtype: %u raw_hwtype: %u\n", __func__, adapter, hwtype, rawtype); /* Tolerated new card level: report calculated type */ *type += (rawtype - hwtype); } return 0; } static int is_min_cex7(unsigned int card) { unsigned int type; int rc; rc = get_card_type(card, &type); if (rc != 0 || type < 7) return 0; return 1; } static int ec_key_apqns_have_valid_version(struct zpc_ec_key *ec_key) { size_t i; /* For all key types we need at least a CEX7 card. More detailed card * version checking (e.g. card firmware level) may follow in future. */ for (i = 0; i < ec_key->napqns; i++) { if (!is_min_cex7(ec_key->apqns[i].card)) return 0; } return 1; } libzpc-1.3.0/src/ecc_key_local.h000066400000000000000000000030121475140344100165110ustar00rootroot00000000000000#ifndef ECC_KEY_LOCAL_H # define ECC_KEY_LOCAL_H /* * Copyright IBM Corp. 2022 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ # include "misc.h" # include "zpc/ecc_key.h" # include # include /* * Internal ecc_key interface. */ enum ec_key_sec { EC_KEY_SEC_CUR = 0, EC_KEY_SEC_OLD = 1, }; struct ec_key { u32 seclen; /* byte-length of secure key blob */ unsigned char sec[MAX_EC_BLOB_SIZE]; }; struct zpc_ec_key { struct ec_key cur; /* old secure key is needed when */ struct ec_key old; /* current is not usable yet */ struct pkey_ecprotkey prot; /* EC protected key derived from sec */ struct pkey_ecpubkey pub; /* EC public key in clear form */ int key_set; int pubkey_set; int curve; int curve_set; unsigned int flags; int flags_set; int type; int type_set; u8 mkvp[MAX_MKVPLEN]; size_t mkvplen; /* byte-length of mkvp */ int mkvp_set; struct pkey_apqn *apqns; size_t napqns; /* elements in apqns */ int apqns_set; unsigned long long refcount; pthread_mutex_t lock; }; int ec_key_clr2sec(struct zpc_ec_key *ec_key, unsigned int flags, const unsigned char *pubkey, unsigned int publen, const unsigned char *privkey, unsigned int privlen); int ec_key_sec2prot(struct zpc_ec_key *, enum ec_key_sec sec); int ec_key_check(const struct zpc_ec_key *); int ec_key_clr2prot(struct zpc_ec_key *ec_key, const unsigned char *privkey, unsigned int privlen); #endif libzpc-1.3.0/src/ecdsa_ctx.c000066400000000000000000000427601475140344100157020ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include "zpc/error.h" #include "zpc/ecdsa_ctx.h" #include "ecc_key_local.h" #include "ecdsa_ctx_local.h" #include "cpacf.h" #include "globals.h" #include "misc.h" #include "debug.h" #include "zkey/pkey.h" #include #include #include #include #include extern const size_t curve2siglen[]; static int __ec_sign(struct zpc_ecdsa_ctx *, const unsigned char *hash, unsigned int hash_len, unsigned char *signature, unsigned int *sig_len); static int __ec_verify(struct zpc_ecdsa_ctx *, const unsigned char *hash, unsigned int hash_len, const unsigned char *signature, unsigned int sig_len); static void __ec_ctx_reset(struct zpc_ecdsa_ctx *); static void __copy_hash_to_sign_param(struct zpc_ecdsa_ctx *ctx, const unsigned char *hash, unsigned int hash_len); static void __get_signature_from_sign_param(struct zpc_ecdsa_ctx *ctx, unsigned char *signature, unsigned int sig_len); static void __copy_pubkey_to_verify_param(struct zpc_ecdsa_ctx *ctx); static void __copy_protkey_to_sign_param(struct zpc_ecdsa_ctx *ctx); static void __copy_args_to_verify_param(struct zpc_ecdsa_ctx *ctx, const unsigned char *hash, unsigned int hash_len, const unsigned char *signature, unsigned int sig_len); static void __cleanup_verify_param(struct zpc_ecdsa_ctx *ctx); static void __cleanup_sign_param(struct zpc_ecdsa_ctx *ctx); size_t group_size[] = { 32, 48, 66 }; int zpc_ecdsa_ctx_alloc(struct zpc_ecdsa_ctx **ec_ctx) { struct zpc_ecdsa_ctx *new_ec_ctx = NULL; int rc; if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.ecc_kdsa) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (ec_ctx == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } new_ec_ctx = calloc(1, sizeof(*new_ec_ctx)); if (new_ec_ctx == NULL) { rc = ZPC_ERROR_MALLOC; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } DEBUG("ec-ctx context at %p: allocated", new_ec_ctx); *ec_ctx = new_ec_ctx; rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_ecdsa_ctx_set_key(struct zpc_ecdsa_ctx *ec_ctx, struct zpc_ec_key *ec_key) { int rc, rv; const unsigned int fc_sign_from_curve[] = { CPACF_KDSA_ENCRYPTED_ECDSA_SIGN_P256, CPACF_KDSA_ENCRYPTED_ECDSA_SIGN_P384, CPACF_KDSA_ENCRYPTED_ECDSA_SIGN_P521, CPACF_KDSA_ENCRYPTED_EDDSA_SIGN_ED25519, CPACF_KDSA_ENCRYPTED_EDDSA_SIGN_ED448, }; const unsigned int fc_verify_from_curve[] = { CPACF_KDSA_ECDSA_VERIFY_ECP256, CPACF_KDSA_ECDSA_VERIFY_ECP384, CPACF_KDSA_ECDSA_VERIFY_ECP521, CPACF_KDSA_EDDSA_VERIFY_ED25519, CPACF_KDSA_EDDSA_VERIFY_ED448, }; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (!hwcaps.ecc_kdsa) { rc = ZPC_ERROR_HWCAPS; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (ec_ctx == NULL) { rc = ZPC_ERROR_ARG1NULL; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } if (ec_key == NULL) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("ec-ctx context at %p: key unset", ec_ctx); __ec_ctx_reset(ec_ctx); rc = 0; DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } rv = pthread_mutex_lock(&ec_key->lock); assert(rv == 0); rc = ec_key_check(ec_key); if (rc) goto ret; if (ec_ctx->ec_key == ec_key) { DEBUG("ec-ctx context at %p: key at %p already set", ec_ctx, ec_key); rc = 0; /* nothing to do */ goto ret; } ec_key->refcount++; DEBUG("ec key at %p: refcount %llu", ec_key, ec_key->refcount); if (ec_ctx->key_set) { /* If another key is already set, unset it and decrease * refcount. */ DEBUG("ec-ctx context at %p: key unset", ec_ctx); __ec_ctx_reset(ec_ctx); } /* Set new key. */ assert(!ec_ctx->key_set); DEBUG("ec-ctx context at %p: key at %p set", ec_ctx, ec_key); if (!ec_key->curve_set) { DEBUG("ec-ctx context at %p: key has no curve property", ec_ctx); rc = ZPC_ERROR_EC_CURVE_NOTSET; goto ret; } ec_ctx->fc_sign = fc_sign_from_curve[ec_key->curve]; ec_ctx->fc_verify = fc_verify_from_curve[ec_key->curve]; ec_ctx->ec_key = ec_key; ec_ctx->key_set = 1; if (ec_key->key_set) __copy_protkey_to_sign_param(ec_ctx); if (ec_key->pubkey_set) __copy_pubkey_to_verify_param(ec_ctx); rc = 0; ret: rv = pthread_mutex_unlock(&ec_key->lock); assert(rv == 0); DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_ecdsa_sign(struct zpc_ecdsa_ctx *ctx, const unsigned char *hash, unsigned int hash_len, unsigned char *signature, unsigned int *sig_len) { int rc, rv, i; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.ecc_kdsa) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (ctx == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if (!ctx->key_set) { rc = ZPC_ERROR_EC_PRIVKEY_NOTSET; goto ret; } if (ctx->ec_key->curve == ZPC_EC_CURVE_P256 || ctx->ec_key->curve == ZPC_EC_CURVE_P384 || ctx->ec_key->curve == ZPC_EC_CURVE_P521) { if (hash == NULL || hash_len == 0) { rc = ZPC_ERROR_ARG2NULL; goto ret; } } /* If the hash/msg is longer than the group size, truncate the input * according to NIST SP 800-107, section 5.1 Truncated Message Digest: * use leftmost bytes and discard rightmost bytes. * For p521 CPACF requires the 7 leftmost bytes to be zero to form a 521 * bit input. */ if (ctx->ec_key->curve == ZPC_EC_CURVE_P256 || ctx->ec_key->curve == ZPC_EC_CURVE_P384 || ctx->ec_key->curve == ZPC_EC_CURVE_P521) { if (hash_len > group_size[ctx->ec_key->curve]) { hash_len = group_size[ctx->ec_key->curve]; } } if (signature == NULL) { *sig_len = curve2siglen[ctx->ec_key->curve]; rc = 0; goto ret; } if (*sig_len < curve2siglen[ctx->ec_key->curve]) { rc = ZPC_ERROR_SMALLOUTBUF; goto ret; } rc = -1; for (i = 0; i < 2 && rc != 0; i++) { assert(i == EC_KEY_SEC_CUR || i == EC_KEY_SEC_OLD); for (;;) { rc = __ec_sign(ctx, hash, hash_len, signature, sig_len); if (rc == 0) { break; } else { if (rc == ZPC_ERROR_WKVPMISMATCH) { rv = pthread_mutex_lock(&ctx->ec_key->lock); assert(rv == 0); DEBUG("ec context at %p: re-derive protected key from %s secure key from ec key at %p", ctx, i == 0 ? "current" : "old", ctx->ec_key); rc = ec_key_sec2prot(ctx->ec_key, i); __copy_protkey_to_sign_param(ctx); rv = pthread_mutex_unlock(&ctx->ec_key->lock); assert(rv == 0); } if (rc) break; } } } ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } int zpc_ecdsa_verify(struct zpc_ecdsa_ctx *ctx, const unsigned char *hash, unsigned int hash_len, const unsigned char *signature, unsigned int sig_len) { int rc, rv; UNUSED(rv); if (pkeyfd < 0) { rc = ZPC_ERROR_DEVPKEY; goto ret; } if (!hwcaps.ecc_kdsa) { rc = ZPC_ERROR_HWCAPS; goto ret; } if (ctx == NULL) { rc = ZPC_ERROR_ARG1NULL; goto ret; } if (ctx->ec_key == NULL) { rc = ZPC_ERROR_EC_NO_KEY_PARTS; goto ret; } if (ctx->ec_key->curve == ZPC_EC_CURVE_P256 || ctx->ec_key->curve == ZPC_EC_CURVE_P384 || ctx->ec_key->curve == ZPC_EC_CURVE_P521) { if (hash == NULL || hash_len == 0) { rc = ZPC_ERROR_ARG2NULL; goto ret; } } if (ctx->ec_key->curve == ZPC_EC_CURVE_P256 || ctx->ec_key->curve == ZPC_EC_CURVE_P384 || ctx->ec_key->curve == ZPC_EC_CURVE_P521) { if (hash_len > group_size[ctx->ec_key->curve]) { hash_len = group_size[ctx->ec_key->curve]; } } if (signature == NULL || sig_len == 0) { rc = ZPC_ERROR_ARG3NULL; goto ret; } if (sig_len != curve2siglen[ctx->ec_key->curve]) { rc = ZPC_ERROR_EC_SIGNATURE_LENGTH; goto ret; } if (!ctx->ec_key->pubkey_set) { rc = ZPC_ERROR_EC_PUBKEY_NOTSET; goto ret; } rc = __ec_verify(ctx, hash, hash_len, signature, sig_len); ret: DEBUG("return %d (%s)", rc, zpc_error_string(rc)); return rc; } void zpc_ecdsa_ctx_free(struct zpc_ecdsa_ctx **ctx) { if (ctx == NULL) return; if (*ctx == NULL) return; if ((*ctx)->key_set) { /* Decrease EC key's refcount. */ zpc_ec_key_free(&(*ctx)->ec_key); (*ctx)->key_set = 0; } __ec_ctx_reset(*ctx); free(*ctx); *ctx = NULL; DEBUG("return"); } static int __ec_sign(struct zpc_ecdsa_ctx *ctx, const unsigned char *hash, unsigned int hash_len, unsigned char *signature, unsigned int *sig_len) { void *param; int rc, cc; if (!ctx->ec_key->key_set) { rc = ZPC_ERROR_EC_PRIVKEY_NOTSET; goto err; } param = &ctx->signbuf; __copy_hash_to_sign_param(ctx, hash, hash_len); cc = cpacf_kdsa(ctx->fc_sign, param, hash, hash_len); assert(cc == 0 || cc == 1 || cc == 2); if (cc == 1) { rc = ZPC_ERROR_WKVPMISMATCH; goto err; } *sig_len = curve2siglen[ctx->ec_key->curve]; __get_signature_from_sign_param(ctx, signature, *sig_len); __cleanup_sign_param(ctx); rc = 0; err: return rc; } static int __ec_verify(struct zpc_ecdsa_ctx *ctx, const unsigned char *hash, unsigned int hash_len, const unsigned char *signature, unsigned int sig_len) { void *param; int rc = ZPC_ERROR_EC_SIGNATURE_INVALID, cc; if (!ctx->ec_key->pubkey_set) { rc = ZPC_ERROR_EC_PUBKEY_NOTSET; goto err; } __copy_args_to_verify_param(ctx, hash, hash_len, signature, sig_len); param = &ctx->verifybuf; cc = cpacf_kdsa(ctx->fc_verify, param, hash, hash_len); if (cc == 0) rc = 0; __cleanup_verify_param(ctx); err: return rc; } static void __ec_ctx_reset(struct zpc_ecdsa_ctx *ctx) { assert(ctx != NULL); memset(&ctx->signbuf, 0, sizeof(ctx->signbuf)); if (ctx->ec_key != NULL) zpc_ec_key_free(&ctx->ec_key); ctx->key_set = 0; ctx->fc_sign = 0; ctx->fc_verify = 0; } static void __copy_hash_to_sign_param(struct zpc_ecdsa_ctx *ctx, const unsigned char *hash, unsigned int hash_len) { switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: memset(ctx->p256_sign_param.hash, 0, 32); memcpy(ctx->p256_sign_param.hash + 32 - hash_len, hash, hash_len); break; case ZPC_EC_CURVE_P384: memset(ctx->p384_sign_param.hash, 0, 48); memcpy(ctx->p384_sign_param.hash + 48 - hash_len, hash, hash_len); break; case ZPC_EC_CURVE_P521: memset(ctx->p521_sign_param.hash, 0, 80); memcpy(ctx->p521_sign_param.hash + 80 - hash_len, hash, hash_len); break; case ZPC_EC_CURVE_ED25519: case ZPC_EC_CURVE_ED448: /* For ED curves do nothing: the input hash is specified via KDSA * parms, not in the CPACF parm block. */ break; } } static void __get_signature_from_sign_param(struct zpc_ecdsa_ctx *ctx, unsigned char *signature, unsigned int sig_len) { switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: memcpy(signature, ctx->p256_sign_param.sig_r, 32); memcpy(signature + sizeof(ctx->p256_sign_param.sig_r), ctx->p256_sign_param.sig_s, 32); break; case ZPC_EC_CURVE_P384: memcpy(signature, ctx->p384_sign_param.sig_r, 48); memcpy(signature + sizeof(ctx->p384_sign_param.sig_r), ctx->p384_sign_param.sig_s, 48); break; case ZPC_EC_CURVE_P521: memcpy(signature, ctx->p521_sign_param.sig_r + 80 - 66, sig_len / 2); memcpy(signature + (sig_len / 2), ctx->p521_sign_param.sig_s + 80 - 66, sig_len / 2); break; case ZPC_EC_CURVE_ED25519: s390_flip_endian_32(signature, ctx->ed25519_sign_param.sig_r); s390_flip_endian_32(signature + 32, ctx->ed25519_sign_param.sig_s); break; case ZPC_EC_CURVE_ED448: s390_flip_endian_64(ctx->ed448_sign_param.sig_r, ctx->ed448_sign_param.sig_r); s390_flip_endian_64(ctx->ed448_sign_param.sig_s, ctx->ed448_sign_param.sig_s); memcpy(signature, ctx->ed448_sign_param.sig_r, 57); memcpy(signature + 57, ctx->ed448_sign_param.sig_s, 57); break; } } static void __copy_pubkey_to_verify_param(struct zpc_ecdsa_ctx *ctx) { unsigned char *pubkey = (unsigned char *)&ctx->ec_key->pub.pubkey; size_t publen = ctx->ec_key->pub.publen; switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: memcpy(ctx->p256_verify_param.pub_x, pubkey, publen); break; case ZPC_EC_CURVE_P384: memcpy(ctx->p384_verify_param.pub_x, pubkey, publen); break; case ZPC_EC_CURVE_P521: memcpy(ctx->p521_verify_param.pub_x + 80 - (publen / 2), pubkey, publen / 2); memcpy(ctx->p521_verify_param.pub_y + 80 - (publen / 2), pubkey + (publen / 2), publen / 2); break; case ZPC_EC_CURVE_ED25519: s390_flip_endian_32(ctx->ed25519_verify_param.pub, pubkey); break; case ZPC_EC_CURVE_ED448: memcpy(ctx->ed448_verify_param.pub, pubkey, publen); s390_flip_endian_64(ctx->ed448_verify_param.pub, ctx->ed448_verify_param.pub); break; } } static void __copy_protkey_to_sign_param(struct zpc_ecdsa_ctx *ctx) { u8 *protkey = (unsigned char *)&ctx->ec_key->prot.protkey; switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: memcpy(ctx->p256_sign_param.prot, protkey, 32); memcpy(ctx->p256_sign_param.wkvp, protkey + 32, 32); break; case ZPC_EC_CURVE_P384: memcpy(ctx->p384_sign_param.prot, protkey, 48); memcpy(ctx->p384_sign_param.wkvp, protkey + 48, 32); break; case ZPC_EC_CURVE_P521: memcpy(ctx->p521_sign_param.prot, protkey, 80); memcpy(ctx->p521_sign_param.wkvp, protkey + 80, 32); break; case ZPC_EC_CURVE_ED25519: memcpy(ctx->ed25519_sign_param.prot, protkey, 32); memcpy(ctx->ed25519_sign_param.wkvp, protkey + 32, 32); break; case ZPC_EC_CURVE_ED448: memcpy(ctx->ed448_sign_param.prot, protkey, 64); memcpy(ctx->ed448_sign_param.wkvp, protkey + 64, 32); break; } } static void __copy_args_to_verify_param(struct zpc_ecdsa_ctx *ctx, const unsigned char *hash, unsigned int hash_len, const unsigned char *signature, unsigned int sig_len) { switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: memset(ctx->p256_verify_param.hash, 0, 32); memcpy(ctx->p256_verify_param.hash + 32 - hash_len, hash, hash_len); memcpy(ctx->p256_verify_param.sig_r, signature, sig_len); break; case ZPC_EC_CURVE_P384: memset(ctx->p384_verify_param.hash, 0, 48); memcpy(ctx->p384_verify_param.hash + 48 - hash_len, hash, hash_len); memcpy(ctx->p384_verify_param.sig_r, signature, sig_len); break; case ZPC_EC_CURVE_P521: memset(ctx->p521_verify_param.hash, 0, 80); memcpy(ctx->p521_verify_param.hash + 80 - hash_len, hash, hash_len); memcpy(ctx->p521_verify_param.sig_r + 80 - (sig_len / 2), signature, sig_len / 2); memcpy(ctx->p521_verify_param.sig_s + 80 - (sig_len / 2), signature + (sig_len / 2), sig_len / 2); break; case ZPC_EC_CURVE_ED25519: s390_flip_endian_32(ctx->ed25519_verify_param.sig_r, signature); s390_flip_endian_32(ctx->ed25519_verify_param.sig_s, signature + 32); break; case ZPC_EC_CURVE_ED448: memcpy(ctx->ed448_verify_param.sig_r, signature, sig_len / 2); memcpy(ctx->ed448_verify_param.sig_s, signature + (sig_len / 2), sig_len / 2); s390_flip_endian_64(ctx->ed448_verify_param.sig_r, ctx->ed448_verify_param.sig_r); s390_flip_endian_64(ctx->ed448_verify_param.sig_s, ctx->ed448_verify_param.sig_s); break; } } static void __cleanup_sign_param(struct zpc_ecdsa_ctx *ctx) { switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: memset(ctx->p256_sign_param.hash, 0, sizeof(ctx->p256_sign_param.hash)); /* zeroize both, sig_r and sig_s */ memset(ctx->p256_sign_param.sig_r, 0, sizeof(ctx->p256_sign_param.sig_r) + sizeof(ctx->p256_sign_param.sig_s)); break; case ZPC_EC_CURVE_P384: memset(ctx->p384_sign_param.hash, 0, sizeof(ctx->p384_sign_param.hash)); /* zeroize both, sig_r and sig_s */ memset(ctx->p384_sign_param.sig_r, 0, sizeof(ctx->p384_sign_param.sig_r) + sizeof(ctx->p384_sign_param.sig_s)); break; case ZPC_EC_CURVE_P521: memset(ctx->p521_sign_param.hash, 0, sizeof(ctx->p521_sign_param.hash)); /* zeroize both, sig_r and sig_s */ memset(ctx->p521_sign_param.sig_r, 0, sizeof(ctx->p521_sign_param.sig_r) + sizeof(ctx->p521_sign_param.sig_s)); break; case ZPC_EC_CURVE_ED25519: /* zeroize both, sig_r and sig_s */ memset(ctx->ed25519_sign_param.sig_r, 0, sizeof(ctx->ed25519_sign_param.sig_r) + sizeof(ctx->ed25519_sign_param.sig_s)); break; case ZPC_EC_CURVE_ED448: /* zeroize both, sig_r and sig_s */ memset(ctx->ed448_sign_param.sig_r, 0, sizeof(ctx->ed448_sign_param.sig_r) + sizeof(ctx->ed448_sign_param.sig_s)); break; } } static void __cleanup_verify_param(struct zpc_ecdsa_ctx *ctx) { switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: memset(ctx->p256_verify_param.hash, 0, sizeof(ctx->p256_verify_param.hash)); /* zeroize both, sig_r and sig_s */ memset(ctx->p256_verify_param.sig_r, 0, sizeof(ctx->p256_verify_param.sig_r) + sizeof(ctx->p256_verify_param.sig_s)); break; case ZPC_EC_CURVE_P384: memset(ctx->p384_verify_param.hash, 0, sizeof(ctx->p384_verify_param.hash)); /* zeroize both, sig_r and sig_s */ memset(ctx->p384_verify_param.sig_r, 0, sizeof(ctx->p384_verify_param.sig_r) + sizeof(ctx->p384_verify_param.sig_s)); break; case ZPC_EC_CURVE_P521: memset(ctx->p521_verify_param.hash, 0, sizeof(ctx->p521_verify_param.hash)); /* zeroize both, sig_r and sig_s */ memset(ctx->p521_verify_param.sig_r, 0, sizeof(ctx->p521_verify_param.sig_r) + sizeof(ctx->p521_verify_param.sig_s)); break; case ZPC_EC_CURVE_ED25519: /* zeroize both, sig_r and sig_s */ memset(ctx->ed25519_verify_param.sig_r, 0, sizeof(ctx->ed25519_verify_param.sig_r) + sizeof(ctx->ed25519_verify_param.sig_s)); break; case ZPC_EC_CURVE_ED448: /* zeroize both, sig_r and sig_s */ memset(ctx->ed448_verify_param.sig_r, 0, sizeof(ctx->ed448_verify_param.sig_r) + sizeof(ctx->ed448_verify_param.sig_s)); break; } } libzpc-1.3.0/src/ecdsa_ctx_local.h000066400000000000000000000020651475140344100170530ustar00rootroot00000000000000/* * Copyright IBM Corp. 2022 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef ECDSA_CTX_LOCAL_H # define ECDSA_CTX_LOCAL_H # include "zpc/ecc_key.h" # include "misc.h" # include "cpacf.h" /* * Internal ecc_ctx interfaces. */ struct zpc_ecdsa_ctx { union { unsigned char signbuf[4096]; struct cpacf_ecp256_sign_param p256_sign_param; struct cpacf_ecp384_sign_param p384_sign_param; struct cpacf_ecp521_sign_param p521_sign_param; struct cpacf_ed25519_sign_param ed25519_sign_param; struct cpacf_ed448_sign_param ed448_sign_param; }; union { unsigned char verifybuf[4096]; struct cpacf_ecp256_verify_param p256_verify_param; struct cpacf_ecp384_verify_param p384_verify_param; struct cpacf_ecp521_verify_param p521_verify_param; struct cpacf_ed25519_verify_param ed25519_verify_param; struct cpacf_ed448_verify_param ed448_verify_param; }; struct zpc_ec_key *ec_key; int key_set; unsigned int fc_sign; unsigned int fc_verify; }; #endif libzpc-1.3.0/src/error.c000066400000000000000000000067301475140344100150730ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "zpc/error.h" #include /* * Map error code to error string. */ const char * zpc_error_string(int err) { /* Error string index equals error code. */ static const char *errstr[] = { "success", "argument 1 NULL", "argument 2 NULL", "argument 3 NULL", "argument 4 NULL", "argument 5 NULL", "argument 6 NULL", "argument 7 NULL", "argument 8 NULL", "argument 1 out of range", "argument 2 out of range", "argument 3 out of range", "argument 4 out of range", "argument 5 out of range", "argument 6 out of range", "argument 7 out of range", "argument 8 out of range", "malloc failed", "no key is set", "invalid key size", "IV not set", "invalid IV size", "invalid tag size", "tag mismatch", "function not supported", "output buffer too small", "APQNs not set", "invalid key type", "key type not set", "PKEY_GENSECK2 ioctl failed", "PKEY_CLR2SECK2 ioctl failed", "PKEY_BLOB2PROTK2 ioctl failed", "wrapping key verification pattern mismatch", "opening /dev/pkey failed", "ciphertext too long", "message too long", "additional authenticated data too long", "RESERVED", "parse error", "APQN not found in APQN list", "MKVP too long", "RESERVED", "initializing a lock failed", "object is in use", "PKEY_APQNS4KT ioctl failed", "key-size not set", "PKEY_GENPROTK ioctl failed", "protected-key only", "keys are equal", "not supported", "Invalid EC curve", "EC curve not set", "EC private key not set", "EC public key not set", "No EC key parts given", "signature invalid", "PKEY_BLOB2PROTK3 ioctl failed", "PKEY_CLR2SECK3 ioctl failed", "No APQNs set for this key, but required for this operation", "Signature length is invalid for this EC key", "Given public/private key parts are inconsistent", "CCA host library not available, but required for this operation", "EP11 host library not available, but required for this operation", "The given EC public key length is invalid", "The given EC private key length is invalid", "The given buffer does not contain a valid CCA secure key token", "The given buffer does not contain a valid EP11 secure key token", "The imported buffer contains an EP11 SPKI with an invalid length", "The imported buffer contains an EP11 SPKI with an invalid EC curve", "The imported buffer contains an EP11 SPKI with an invalid public key", "The imported buffer contains an EP11 MACed SPKI with an invalid MKVP", "The imported buffer contains a key blob that cannot be transformed into a protected key.", "At least one APQN version is invalid for this function.", "The given buffer does not contain a valid EP11 AES secure key token.", "The given buffer does not contain a valid CCA datakey token", "The given buffer does not contain a valid CCA cipherkey token", "Error creating random bytes", "Invalid usage of a gcm context with an internally created iv", "Support for UV retrievable secrets is not available, but required for this function.", "The given pvsecret type is not supported by libzpc.", "The given pvsecret ID does not belong to a secret on this system.", "PKEY_VERIFYKEY2 ioctl failed.", "LAST" }; const char *rc; if (err < 0 || (size_t)err >= sizeof(errstr) / sizeof(errstr[0])) rc = "undefined error code"; else rc = errstr[err]; return rc; } libzpc-1.3.0/src/globals.c000066400000000000000000000315501475140344100153630ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "aes_key_local.h" #include "cpacf.h" #include "globals.h" #include "misc.h" #include "debug.h" #include #include #include #include #include #include #include #include #include #include #define ENV_DEBUG "ZPC_DEBUG" /* * IBM z/Architecture Principles of Operation (POP) counts bits * from most-significant/leftmost to least-significant/rightmost, * starting at 0. * If the bits returned by STFLE (facility list) or the bits * returned by a CPACF instruction's query function (status word) * are stored in an u64 array, the macros below can be used to * check a specific bit using its number from POP. * For example, checking facility bit 146: * u64 *flist; * [...] // store facility list at flist * if (flist[OFF64(146)] & MASK64(146)) [...]; */ /* Map a facility bit number or function code to its bit mask. */ #define MASK64(n) (1ULL << (63 - (n) % 64)) /* Map a facility bit number or function code to its offset. */ #define OFF64(n) (n / 64) /* Facility bit numbers */ #define MSA 17 /* message-security-assist */ #define MSA3 76 /* message-security-assist extension 3 */ #define MSA4 77 /* message-security-assist extension 4 */ #define MSA5 57 /* message-security-assist extension 5 */ #define MSA8 146 /* message-security-assist extension 8 (implies MSA3) */ #define MSA9 155 /* message-security-assist extension 9 (implies MSA3 * and MSA4) */ /* STFLE (store facility list extended) */ static inline unsigned long stfle(u64 flist[], u8 nmemb) { /* *INDENT-OFF* */ register unsigned long r0 __asm__("0") = (unsigned long)nmemb - 1; __asm__ volatile( ".insn s,%[opc]<<16,0(%[flist])" : "+d" (r0) : [flist] "a" (flist), [opc] "i" (0xb2b0) : "memory", "cc" ); /* *INDENT-ON* */ return r0 + 1; } /* * libzpc is initialized iff pkeyfd >= 0. * * Make sure this global (or another one from this compilation unit) * is referenced from all other compilation units that require the * constructor to run (that is probably all units except for the * error unit). * In case libzpc was compiled to a static library/archive, this makes sure * that the object file corresponding to this compilation unit is included * when the archive is linked with another binary. * This is because this file's constructor and destructor are required * for libzpc to work properly but are never referenced otherwise, * so the linker will generally not pick this object from the archive * unless the --whole-archive option was specified. */ int pkeyfd = -1; struct hwcaps hwcaps; struct swcaps swcaps; int debug; pthread_mutex_t debuglock; struct cca_lib cca; pthread_mutex_t ccalock; struct ep11_lib ep11; pthread_mutex_t ep11lock; #if !defined(__linux__) && !defined(__s390x__) static const int init = 0; #else static const int init = 1; #endif __attribute__((constructor)) static void zpc_init(void) { unsigned long hwcap, facility_list_nmemb; u64 status_word[2], *facility_list = NULL, tmp; int rc, err = -1; int aes_ecb_km = 0; int aes_cbc_kmc = 0; int aes_gcm_kma = 0; int aes_cmac_kmac = 0, aes_cmac_pcc = 0; int aes_ccm_kmac = 0, aes_ccm_kma = 0; int aes_xts_km = 0, aes_xts_pcc = 0; int ecc_kdsa = 0; int aes_cca = 0, aes_ep11 = 0, ecdsa_cca = 0, ecdsa_ep11 = 0; int uv_pvsecrets = 0; char *env; if (init != 1) return; /* Init debuggind. */ rc = pthread_mutex_init(&debuglock, NULL); if (rc) goto ret; env = getenv(ENV_DEBUG); if (env != NULL && env[0] != '\0') { char *endptr; long debuglong = strtol(env, &endptr, 0); if (*endptr == '\0' && debuglong > INT_MIN && debuglong < INT_MAX) debug = (int)debuglong; } /* Init CCA library structure. */ rc = pthread_mutex_init(&ccalock, NULL); if (rc) goto ret; rc = pthread_mutex_lock(&ccalock); assert(rc == 0); if (load_cca_library(&cca, true) != 0) { DEBUG("loading CCA library failed"); } else { DEBUG("loaded CCA library: ver %u, rel %u, mod %u", cca.version.ver, cca.version.rel, cca.version.mod); aes_cca = 1; if (cca.version.ver >= 7) ecdsa_cca = 1; } rc = pthread_mutex_unlock(&ccalock); assert(rc == 0); /* Init EP11 library structure. */ rc = pthread_mutex_init(&ep11lock, NULL); if (rc) goto ret; rc = pthread_mutex_lock(&ep11lock); assert(rc == 0); if (load_ep11_library(&ep11, true) != 0) { DEBUG("loading EP11 library failed"); } else { DEBUG("loaded EP11 library: %u.%u", ep11.version.major, ep11.version.minor); aes_ep11 = 1; if (ep11.version.major >= 3) ecdsa_ep11 = 1; } rc = pthread_mutex_unlock(&ep11lock); assert(rc == 0); /* * Check if we are running in a Secure Execution guest with retrievable * secret support */ if (running_in_se_guest() && max_secrets() > 0) uv_pvsecrets = 1; /* Open pkey device */ pkeyfd = open("/dev/pkey", O_RDWR); if (pkeyfd < 0) { DEBUG("opening /dev/pkey failed"); goto ret; } DEBUG("opened /dev/pkey: file descriptor %d", pkeyfd); /* Check for STFLE. */ hwcap = getauxval(AT_HWCAP); if (!(hwcap & HWCAP_S390_STFLE)) goto ret; /* Query number of u64s returned by stfle. */ facility_list_nmemb = stfle(&tmp, 1); if (facility_list_nmemb > UINT8_MAX) goto ret; /* Expected facility list size is 64 * facility_list_nmemb bits. */ facility_list = calloc(facility_list_nmemb, sizeof(u64)); if (facility_list == NULL) goto ret; /* Query facility list. */ stfle(facility_list, facility_list_nmemb); /* Check MSA. */ if (facility_list_nmemb >= OFF64(MSA) + 1 && (facility_list[OFF64(MSA)] & MASK64(MSA))) { DEBUG("detected message-security-assist"); memset(status_word, 0, sizeof(status_word)); cpacf_km(CPACF_KM_QUERY, &status_word, NULL, NULL, 0); DEBUG("status word km: 0x%016llx:0x%016llx", status_word[0], status_word[1]); if ((status_word[OFF64(CPACF_KM_ENCRYPTED_AES_128)] & MASK64(CPACF_KM_ENCRYPTED_AES_128)) && (status_word[OFF64(CPACF_KM_ENCRYPTED_AES_192)] & MASK64(CPACF_KM_ENCRYPTED_AES_192)) && (status_word[OFF64(CPACF_KM_ENCRYPTED_AES_256)] & MASK64(CPACF_KM_ENCRYPTED_AES_256))) { aes_ecb_km = 1; } if ((status_word[OFF64(CPACF_KM_XTS_ENCRYPTED_AES_128)] & MASK64(CPACF_KM_XTS_ENCRYPTED_AES_128)) && (status_word[OFF64(CPACF_KM_XTS_ENCRYPTED_AES_256)] & MASK64(CPACF_KM_XTS_ENCRYPTED_AES_256))) { aes_xts_km = 1; } memset(status_word, 0, sizeof(status_word)); cpacf_kmc(CPACF_KMC_QUERY, &status_word, NULL, NULL, 0); DEBUG("status word kmc: 0x%016llx:0x%016llx", status_word[0], status_word[1]); if ((status_word[OFF64(CPACF_KMC_ENCRYPTED_AES_128)] & MASK64(CPACF_KMC_ENCRYPTED_AES_128)) && (status_word[OFF64(CPACF_KMC_ENCRYPTED_AES_192)] & MASK64(CPACF_KMC_ENCRYPTED_AES_192)) && (status_word[OFF64(CPACF_KMC_ENCRYPTED_AES_256)] & MASK64(CPACF_KMC_ENCRYPTED_AES_256))) { aes_cbc_kmc = 1; } memset(status_word, 0, sizeof(status_word)); cpacf_kmac(CPACF_KMAC_QUERY, &status_word, NULL, 0); DEBUG("status word kmac: 0x%016llx:0x%016llx", status_word[0], status_word[1]); if ((status_word[OFF64(CPACF_KMAC_ENCRYPTED_AES_128)] & MASK64(CPACF_KMAC_ENCRYPTED_AES_128)) && (status_word[OFF64(CPACF_KMAC_ENCRYPTED_AES_192)] & MASK64(CPACF_KMAC_ENCRYPTED_AES_192)) && (status_word[OFF64(CPACF_KMAC_ENCRYPTED_AES_256)] & MASK64(CPACF_KMAC_ENCRYPTED_AES_256))) { aes_cmac_kmac = 1; aes_ccm_kmac = 1; } } /* Check MSA3. */ if (facility_list_nmemb >= OFF64(MSA3) + 1 && (facility_list[OFF64(MSA3)] & MASK64(MSA3))) { DEBUG("detected message-security-assist extension 3"); memset(status_word, 0, sizeof(status_word)); cpacf_pcc(CPACF_PCC_QUERY, &status_word); DEBUG("status word pcc: 0x%016llx:0x%016llx", status_word[0], status_word[1]); if ((status_word[OFF64(CPACF_PCC_CMAC_ENCRYPTED_AES_128)] & MASK64(CPACF_PCC_CMAC_ENCRYPTED_AES_128)) && (status_word[OFF64(CPACF_PCC_CMAC_ENCRYPTED_AES_192)] & MASK64(CPACF_PCC_CMAC_ENCRYPTED_AES_192)) && (status_word[OFF64(CPACF_PCC_CMAC_ENCRYPTED_AES_256)] & MASK64(CPACF_PCC_CMAC_ENCRYPTED_AES_256))) { aes_cmac_pcc = 1; } if ((status_word[OFF64(CPACF_PCC_XTS_ENCRYPTED_AES_128)] & MASK64(CPACF_PCC_XTS_ENCRYPTED_AES_128)) && (status_word[OFF64(CPACF_PCC_XTS_ENCRYPTED_AES_256)] & MASK64(CPACF_PCC_XTS_ENCRYPTED_AES_256))) { aes_xts_pcc = 1; } } /* Check MSA8. */ if (facility_list_nmemb >= OFF64(MSA8) + 1 && (facility_list[OFF64(MSA8)] & MASK64(MSA8))) { DEBUG("detected message-security-assist extension 8"); memset(status_word, 0, sizeof(status_word)); cpacf_kma(CPACF_KMA_QUERY, &status_word, NULL, NULL, 0, NULL, 0); DEBUG("status word kma: 0x%016llx:0x%016llx", status_word[0], status_word[1]); if ((status_word[OFF64(CPACF_KMA_GCM_ENCRYPTED_AES_128)] & MASK64(CPACF_KMA_GCM_ENCRYPTED_AES_128)) && (status_word[OFF64(CPACF_KMA_GCM_ENCRYPTED_AES_192)] & MASK64(CPACF_KMA_GCM_ENCRYPTED_AES_192)) && (status_word[OFF64(CPACF_KMA_GCM_ENCRYPTED_AES_256)] & MASK64(CPACF_KMA_GCM_ENCRYPTED_AES_256))) { aes_ccm_kma = 1; aes_gcm_kma = 1; } } /* Check MSA9. */ if (facility_list_nmemb >= OFF64(MSA9) + 1 && (facility_list[OFF64(MSA9)] & MASK64(MSA9))) { DEBUG("detected message-security-assist extension 9"); memset(status_word, 0, sizeof(status_word)); cpacf_kdsa(CPACF_KDSA_QUERY, &status_word, NULL, 0); DEBUG("status word kdsa: 0x%016llx:0x%016llx", status_word[0], status_word[1]); if ((status_word[OFF64(CPACF_KDSA_ENCRYPTED_ECDSA_SIGN_P256)] & MASK64(CPACF_KDSA_ENCRYPTED_ECDSA_SIGN_P256)) && (status_word[OFF64(CPACF_KDSA_ENCRYPTED_ECDSA_SIGN_P384)] & MASK64(CPACF_KDSA_ENCRYPTED_ECDSA_SIGN_P384)) && (status_word[OFF64(CPACF_KDSA_ENCRYPTED_ECDSA_SIGN_P521)] & MASK64(CPACF_KDSA_ENCRYPTED_ECDSA_SIGN_P521)) && (status_word[OFF64(CPACF_KDSA_ENCRYPTED_EDDSA_SIGN_ED25519)] & MASK64(CPACF_KDSA_ENCRYPTED_EDDSA_SIGN_ED25519)) && (status_word[OFF64(CPACF_KDSA_ENCRYPTED_EDDSA_SIGN_ED448)] & MASK64(CPACF_KDSA_ENCRYPTED_EDDSA_SIGN_ED448))) { ecc_kdsa = 1; } } /* Hardware capabilities via CPACF */ if (aes_ecb_km == 1) { hwcaps.aes_ecb = 1; DEBUG("detected aes-ecb instruction set extensions"); } if (aes_cbc_kmc == 1) { hwcaps.aes_cbc = 1; DEBUG("detected aes-cbc instruction set extensions"); } if (aes_xts_km == 1 && aes_xts_pcc) { hwcaps.aes_xts = 1; DEBUG("detected aes-xts instruction set extensions"); } if (aes_cmac_kmac == 1 && aes_cmac_pcc == 1) { hwcaps.aes_cmac = 1; DEBUG("detected aes-cmac instruction set extensions"); } if (aes_ccm_kma == 1 && aes_ccm_kmac == 1) { hwcaps.aes_ccm = 1; DEBUG("detected aes-ccm instruction set extensions"); } if (aes_gcm_kma == 1) { hwcaps.aes_gcm = 1; DEBUG("detected aes-gcm instruction set extensions"); } if (ecc_kdsa == 1) { hwcaps.ecc_kdsa = 1; DEBUG("detected ecc-kdsa instruction set extensions"); } /* Software capabilities via host libs */ if (aes_cca == 1) { swcaps.aes_cca = 1; DEBUG("detected aes via cca host lib software capability"); } if (aes_ep11 == 1) { swcaps.aes_ep11 = 1; DEBUG("detected aes via ep11 host lib software capability"); } if (uv_pvsecrets == 1) { swcaps.uv_pvsecrets = 1; DEBUG("detected UV retrievable secrets capability"); } else { DEBUG("UV retrievable secrets capability not available"); } if (ecdsa_cca == 1) { swcaps.ecdsa_cca = 1; DEBUG("detected ecdsa via cca host lib software capability"); } else { DEBUG("ecdsa via cca host lib software capability not available"); } if (ecdsa_ep11 == 1) { swcaps.ecdsa_ep11 = 1; DEBUG("detected ecdsa via ep11 host lib software capability"); } else { DEBUG("ecdsa via ep11 host lib software capability not available"); } err = 0; ret: if (err) { if (pkeyfd >= 0) { close(pkeyfd); pkeyfd = -1; } } free(facility_list); DEBUG("return"); return; } __attribute__((destructor)) static void zpc_fini(void) { int rc; UNUSED(rc); if (init != 1) return; if (pkeyfd >= 0) { close(pkeyfd); pkeyfd = -1; } /* Unload EP11 library. */ rc = pthread_mutex_lock(&ep11lock); assert(rc == 0); if (ep11.lib_ep11 != NULL) dlclose(ep11.lib_ep11); rc = pthread_mutex_unlock(&ep11lock); assert(rc == 0); rc = pthread_mutex_destroy(&ep11lock); assert(rc == 0); /* Unload CCA library. */ rc = pthread_mutex_lock(&ccalock); assert(rc == 0); if (cca.lib_csulcca != NULL) dlclose(cca.lib_csulcca); rc = pthread_mutex_unlock(&ccalock); assert(rc == 0); rc = pthread_mutex_destroy(&ccalock); assert(rc == 0); DEBUG("return"); rc = pthread_mutex_destroy(&debuglock); assert(rc == 0); } libzpc-1.3.0/src/globals.h000066400000000000000000000016361475140344100153720ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef GLOBALS_H # define GLOBALS_H # include # include # include "pvsecrets.h" # include "zkey/cca.h" # include "zkey/ep11.h" struct hwcaps { int aes_gcm; int aes_ccm; int aes_ecb; int aes_cbc; int aes_xts; int aes_cmac; int ecc_kdsa; }; struct swcaps { int aes_cca; int aes_ep11; int uv_pvsecrets; int ecdsa_cca; int ecdsa_ep11; }; /* * Globals are initialized at the library's constructor * and are read-only or lock-protected afterwards. */ extern int pkeyfd; extern struct hwcaps hwcaps; extern struct swcaps swcaps; extern int debug; extern pthread_mutex_t debuglock; extern struct cca_lib cca; extern pthread_mutex_t ccalock; extern struct ep11_lib ep11; extern pthread_mutex_t ep11lock; #endif libzpc-1.3.0/src/misc.c000066400000000000000000000044231475140344100146720ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "misc.h" #include #include #include #include #include static int ishexdigit(const char); static unsigned char hexdigit2byte(char); static char byte2hexdigit(unsigned char); int local_rng(u8 *output, size_t bytes) { int ranfd; int rlen; unsigned int totallen = 0; ranfd = open("/dev/prandom", O_RDONLY); if (ranfd < 0) ranfd = open("/dev/urandom", O_RDONLY); if (ranfd >= 0) { do { rlen = read(ranfd, output + totallen, bytes - totallen); totallen += rlen; } while (totallen < bytes); close(ranfd); return 0; } return -1; } int hexstr2buf(u8 * buf, size_t *buflen, const char *hex) { size_t i; assert(buf != NULL); assert(buflen != NULL); assert(*buflen != 0); assert(hex != NULL); /* Skip possible leading '0x'. */ if (strlen(hex) >= 2 && hex[0] == '0' && hex[1] == 'x') hex += 2; if (strlen(hex) == 0 || strlen(hex) % 2 != 0 || strlen(hex) / 2 > *buflen) return -1; memset(buf, 0, *buflen); for (i = 0; i + 1 < strlen(hex); i += 2) { if (!ishexdigit(hex[i]) || !ishexdigit(hex[i + 1])) return -1; /* Parse error. */ buf[i / 2] = hexdigit2byte(hex[i]) << 4; buf[i / 2] += hexdigit2byte(hex[i + 1]); } *buflen = strlen(hex) / 2; return 0; } void buf2hexstr(char *hex, size_t hexlen, const unsigned char *buf, size_t buflen) { size_t i; assert(hex != NULL); assert(buf != NULL); assert(buflen > 0); assert(hexlen >= 2 * buflen); memset(hex, 0, hexlen); for (i = 0; i < buflen; i++) { hex[2 * i] = byte2hexdigit(buf[i] >> 4); hex[2 * i + 1] = byte2hexdigit(buf[i] & 0xf); } hex[2 * i] = '\0'; } static int ishexdigit(const char d) { return ((d >= '0' && d <= '9') || (d >= 'A' && d <= 'F') || (d >= 'a' && d <= 'f')); } static unsigned char hexdigit2byte(char d) { const char noff = '0' - 0; const char uoff = 'A' - 10; const char loff = 'a' - 10; return (d >= 'a' ? d - loff : (d >= 'A' ? d - uoff : d - noff)); } static char byte2hexdigit(unsigned char b) { const char noff = '0' - 0; const char loff = 'a' - 10; assert((b & 0xf0) == 0); return (b >= 10 ? b + loff : b + noff); } libzpc-1.3.0/src/misc.h000066400000000000000000000014221475140344100146730ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef MISC_H # define MISC_H # include # define UNUSED(x) (void)(x) # define NMEMB(x) (sizeof(x) / sizeof(x[0])) # define __packed __attribute__((packed)) typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64; /* Maximum binary MKVP byte-length. */ # define MAX_MKVPLEN 32 void memzero_secure(void *, size_t); int memcmp_consttime(const void *, const void *, size_t); int hexstr2buf(u8 *, size_t *, const char *); void buf2hexstr(char *, size_t, const unsigned char *, size_t); int local_rng(u8 *output, size_t bytes); #endif libzpc-1.3.0/src/misc_asm.S000066400000000000000000000026201475140344100155070ustar00rootroot00000000000000# # Copyright IBM Corp. 2021 # # libzpc is free software; you can redistribute it and/or modify # it under the terms of the MIT license. See LICENSE for details. # .text # void memzero_secure(void *buf, size_t buflen) .globl memzero_secure .type memzero_secure,@function .align 16 memzero_secure: .cfi_startproc ltgr %r3,%r3 ber %r14 aghi %r3,-1 srlg %r1,%r3,8 ltgr %r1,%r1 je .Lmemzero_secure_skip .Lmemzero_secure_oop: xc 0(256,%r2),0(%r2) la %r2,256(%r2) brctg %r1,.Lmemzero_secure_oop .Lmemzero_secure_skip: larl %r1,.Lmemzero_secure_xc ex %r3,0(%r1) br %r14 .Lmemzero_secure_xc: xc 0(1,%r2),0(%r2) .cfi_endproc .size memzero_secure, .-memzero_secure # int memcmp_consttime(const void *buf1, const void *buf2, size_t buflen) .globl memcmp_consttime .type memcmp_consttime,@function .align 16 memcmp_consttime: .cfi_startproc lghi %r5,0 clgr %r4,%r5 je .Lmemcmp_consttime_skip .Lmemcmp_consttime_loop: llgc %r0,0(%r2) la %r2,1(%r2) llgc %r1,0(%r3) la %r3,1(%r3) xr %r1,%r0 or %r5,%r1 brctg %r4,.Lmemcmp_consttime_loop lnr %r5,%r5 srl %r5,31 .Lmemcmp_consttime_skip: lgr %r2,%r5 br %r14 .cfi_endproc .size memcmp_consttime, .-memcmp_consttime .size memcmp_consttime,.-memcmp_consttime .section .note.GNU-stack,"",@progbits libzpc-1.3.0/src/pvsecrets.c000066400000000000000000000014061475140344100157530ustar00rootroot00000000000000/* * Support for Ultravisor retrievable secrets * * Copyright IBM Corp. 2024 * */ #include #include #include #include #include "pvsecrets.h" #define SE_GUEST "/sys/firmware/uv/prot_virt_guest" #define MAX_SECRETS "/sys/firmware/uv/query/max_secrets" int running_in_se_guest(void) { FILE *fd; char se_flag; if ((fd = fopen(SE_GUEST, "r")) == NULL) return 0; if (fread(&se_flag, sizeof(se_flag), 1, fd) != 1) { fclose(fd); return 0; } fclose(fd); return se_flag - '0' ? 1 : 0; } long max_secrets(void) { FILE *fd; char buf[8] = { 0, }; if ((fd = fopen(MAX_SECRETS, "r")) == NULL) return 0; if (fread(buf, 1, sizeof(buf), fd) == 0) { fclose(fd); return 0; } fclose(fd); return atol(buf); } libzpc-1.3.0/src/pvsecrets.h000066400000000000000000000002761475140344100157640ustar00rootroot00000000000000/* * Support for Ultravisor retrievable secrets * * Copyright IBM Corp. 2024 */ #ifndef PVSECRETS_H #define PVSECRETS_H int running_in_se_guest(void); long max_secrets(void); #endif libzpc-1.3.0/src/zkey/000077500000000000000000000000001475140344100145525ustar00rootroot00000000000000libzpc-1.3.0/src/zkey/README000066400000000000000000000002521475140344100154310ustar00rootroot00000000000000zpc_aes_key_reencipher used modified zkey code from s390-tools-2.18 as a library to reencipher secure keys: https://github.com/ibm-s390-linux/s390-tools/tree/master/zkey libzpc-1.3.0/src/zkey/cca.c000066400000000000000000000730621475140344100154540ustar00rootroot00000000000000/* * zkey - Generate, re-encipher, and validate secure keys * * Copyright IBM Corp. 2019 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include #include #include #include #include #include #include #include #include "lib/util_base.h" #include "lib/util_libc.h" #include "lib/util_panic.h" #include "cca.h" #include "pkey.h" #include "utils.h" #include "debug.h" #define pr_verbose(verbose, fmt...) do { \ if (verbose) \ DEBUG(fmt); \ } while (0) /* * Definitions for the CCA library */ #define CCA_LIBRARY_NAME "libcsulcca.so" #define CCA_WEB_PAGE "http://www.ibm.com/security/cryptocards" #define CCA_DOMAIN_ENVAR "CSU_DEFAULT_DOMAIN" #define CCA_ADAPTER_ENVAR "CSU_DEFAULT_ADAPTER" extern const uint16_t curve2bitlen[]; #define CCA_CURVE_TYPE_PRIME 0 #define CCA_CURVE_TYPE_EDWARDS 2 const uint8_t curve2ccatype[] = { CCA_CURVE_TYPE_PRIME, CCA_CURVE_TYPE_PRIME, CCA_CURVE_TYPE_PRIME, CCA_CURVE_TYPE_EDWARDS, CCA_CURVE_TYPE_EDWARDS }; /** * Prints CCA return and reason code information for certain known CCA * error situations. * * @param return_code the CCA return code * @param reason_code the CCA reason code */ static void print_CCA_error(int return_code, int reason_code) { switch (return_code) { case 8: switch (reason_code) { case 48: DEBUG("The secure key has a CCA master key " "verification pattern that is not valid"); break; case 90: DEBUG("The operation has been rejected due to access " "control checking"); break; case 2143: DEBUG("The operation has been rejected due to key " "export restrictions of the secure key"); break; } break; case 12: switch (reason_code) { case 764: DEBUG("The CCA master key is not loaded and " "therefore a secure key cannot be enciphered"); break; } break; } } /** * Returns the version, release and modification number of the used CCA library. * * @param[in] cca the CCA library structure * @param[in] verbose if true, verbose messages are printed * * @returns 0 on success, a negative errno in case of an error */ static int get_cca_version(struct cca_lib *cca, bool verbose) { unsigned char exit_data[4] = { 0, }; unsigned char version_data[20]; long return_code, reason_code; long version_data_length; long exit_data_len = 0; char date[20]; util_assert(cca != NULL, "Internal error: cca is NULL"); if (cca->lib_csulcca == NULL) { pr_verbose(verbose, "CCA host library not available."); return -ELIBACC; } if (cca->dll_CSUACFV == NULL) { pr_verbose(verbose, "CCA host lib function CSUACFV not " "available but required for getting the CCA library version."); return -ELIBACC; } memset(version_data, 0, sizeof(version_data)); version_data_length = sizeof(version_data); cca->dll_CSUACFV(&return_code, &reason_code, &exit_data_len, exit_data, &version_data_length, version_data); pr_verbose(verbose, "CSUACFV (Cryptographic Facility Version) " "returned: return_code: %ld, reason_code: %ld", return_code, reason_code); if (return_code != 0) { print_CCA_error(return_code, reason_code); return -EIO; } version_data[sizeof(version_data) - 1] = '\0'; pr_verbose(verbose, "CCA Version string: %s", version_data); if (sscanf((char *)version_data, "%u.%u.%uz%s", &cca->version.ver, &cca->version.rel, &cca->version.mod, date) != 4) { DEBUG("CCA library version is invalid: %s", version_data); return -EINVAL; } return 0; } /** * Loads the CCA library and provides the entry point of the CSNBKTC function. * * @param[out] cca on return this contains the address of the CCA * library and certain CCA symbols. dlclose() should * be used to free the library when no longer needed. * @param verbose if true, verbose messages are printed * * @returns 0 on success, -ELIBACC in case of library load errors */ int load_cca_library(struct cca_lib *cca, bool verbose) { util_assert(cca != NULL, "Internal error: cca is NULL"); /* Load the CCA library */ cca->lib_csulcca = dlopen(CCA_LIBRARY_NAME, RTLD_GLOBAL | RTLD_NOW); if (cca->lib_csulcca == NULL) { pr_verbose(verbose, "%s", dlerror()); DEBUG("The command requires the IBM CCA Host Libraries and " "Tools.\nFor the supported environments and downloads, " "see:\n%s", CCA_WEB_PAGE); return -ELIBACC; } /* Get the Cryptographic Facility Version function */ cca->dll_CSUACFV = (t_CSUACFV)dlsym(cca->lib_csulcca, "CSUACFV"); /* Get the Key Token Change function */ cca->dll_CSNBKTC = (t_CSNBKTC)dlsym(cca->lib_csulcca, "CSNBKTC"); /* Get the Key Token Change 2 function */ cca->dll_CSNBKTC2 = (t_CSNBKTC2)dlsym(cca->lib_csulcca, "CSNBKTC2"); /* Get the Cryptographic Facility Query function */ cca->dll_CSUACFQ = (t_CSUACFQ)dlsym(cca->lib_csulcca, "CSUACFQ"); /* Get the Cryptographic Resource Allocate function */ cca->dll_CSUACRA = (t_CSUACRA)dlsym(cca->lib_csulcca, "CSUACRA"); /* Cryptographic Resource Deallocate function */ cca->dll_CSUACRD = (t_CSUACRD)dlsym(cca->lib_csulcca, "CSUACRD"); /* Get the Key Token Build 2 function */ cca->dll_CSNBKTB2 = (t_CSNBKTB2)dlsym(cca->lib_csulcca, "CSNBKTB2"); /* Get the Key Translate 2 function */ cca->dll_CSNBKTR2 = (t_CSNBKTR2)dlsym(cca->lib_csulcca, "CSNBKTR2"); /* Get the Restrict Key Attribute function */ cca->dll_CSNBRKA = (t_CSNBRKA)dlsym(cca->lib_csulcca, "CSNBRKA"); /* Get the PKA Key Token Build function */ cca->dll_CSNDPKB = (t_CSNDPKB)dlsym(cca->lib_csulcca, "CSNDPKB"); /* Get the PKA Key Generate function */ cca->dll_CSNDPKG = (t_CSNDPKG)dlsym(cca->lib_csulcca, "CSNDPKG"); /* Get the PKA Public Key Extract function */ cca->dll_CSNDPKX = (t_CSNDPKX)dlsym(cca->lib_csulcca, "CSNDPKX"); /* Get the PKA Key Import function */ cca->dll_CSNDPKI = (t_CSNDPKI)dlsym(cca->lib_csulcca, "CSNDPKI"); /* Get the PKA Key Token Change function (for ECC keys) */ cca->dll_CSNDKTC = (t_CSNDKTC)dlsym(cca->lib_csulcca, "CSNDKTC"); if (cca->dll_CSUACFV == NULL || cca->dll_CSNBKTC == NULL || cca->dll_CSNBKTC2 == NULL || cca->dll_CSUACFQ == NULL || cca->dll_CSUACRA == NULL || cca->dll_CSUACRD == NULL || cca->dll_CSNBKTB2 == NULL || cca->dll_CSNBKTR2 == NULL || cca->dll_CSNBRKA == NULL || cca->dll_CSNDPKB == NULL || cca->dll_CSNDPKG == NULL || cca->dll_CSNDPKX == NULL || cca->dll_CSNDPKI == NULL || cca->dll_CSNDKTC == NULL) { pr_verbose(verbose, "%s", dlerror()); DEBUG("The command requires the IBM CCA Host Libraries and " "Tools.\nFor the supported environments and downloads, " "see:\n%s", CCA_WEB_PAGE); return -ELIBACC; } pr_verbose(verbose, "CCA library '%s' has been loaded successfully", CCA_LIBRARY_NAME); return get_cca_version(cca, verbose); } /** * Re-enciphers a secure key. * * @param[in] cca the CCA libraray structure * @param[in] secure_key a buffer containing the secure key * @param[in] secure_key_size the size of the secure key * @param[in] method the re-enciphering method. METHOD_OLD_TO_CURRENT * or METHOD_CURRENT_TO_NEW. * @param[in] verbose if true, verbose messages are printed * * @returns 0 on success, -EIO in case of an error */ int key_token_change(struct cca_lib *cca, u8 *secure_key, unsigned int secure_key_size, char *method, bool verbose) { struct aescipherkeytoken *cipherkey = (struct aescipherkeytoken *)secure_key; long exit_data_len = 0, rule_array_count; unsigned char rule_array[2 * 8] = { 0, }; unsigned char exit_data[4] = { 0, }; long return_code, reason_code; long key_token_length; util_assert(cca != NULL, "Internal error: cca is NULL"); util_assert(secure_key != NULL, "Internal error: secure_key is NULL"); util_assert(secure_key_size > 0, "Internal error: secure_key_size is 0"); util_assert(method != NULL, "Internal error: method is NULL"); memcpy(rule_array, method, 8); rule_array_count = 1; if (is_cca_aes_data_key(secure_key, secure_key_size)) { if (cca->dll_CSNBKTC == NULL) { pr_verbose(verbose, "CCA host lib function CSNBKTC not " "available but required for AES data key token change."); return -ELIBACC; } memcpy(rule_array + 8, "AES ", 8); rule_array_count++; cca->dll_CSNBKTC(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, secure_key); pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' " "returned: return_code: %ld, reason_code: %ld", method, return_code, reason_code); } else if (is_cca_aes_cipher_key(secure_key, secure_key_size)) { if (cca->dll_CSNBKTC2 == NULL) { pr_verbose(verbose, "CCA host lib function CSNBKTC2 not " "available but required for AES cipher key token change."); return -ELIBACC; } memcpy(rule_array + 8, "AES ", 8); rule_array_count++; key_token_length = cipherkey->length; cca->dll_CSNBKTC2(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_token_length, (unsigned char *)cipherkey); pr_verbose(verbose, "CSNBKTC2 (Key Token Change2) with '%s' " "returned: return_code: %ld, reason_code: %ld", method, return_code, reason_code); pr_verbose(verbose, "key_token_length: %lu", key_token_length); } else if (is_cca_ec_key(secure_key, secure_key_size)) { if (cca->dll_CSNDKTC == NULL) { pr_verbose(verbose, "CCA host lib function CSNDKTC not " "available but required for ECC key token change."); return -ELIBACC; } memcpy(rule_array + 8, "ECC ", 8); rule_array_count++; key_token_length = secure_key_size; cca->dll_CSNDKTC(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_token_length, secure_key); pr_verbose(verbose, "CSNDKTC (PKA Key Token Change) with '%s' " "returned: return_code: %ld, reason_code: %ld", method, return_code, reason_code); pr_verbose(verbose, "key_token_length: %lu", key_token_length); } else { DEBUG("Invalid key type specified"); return -EINVAL; } if (return_code != 0) { print_CCA_error(return_code, reason_code); return -EIO; } if (is_xts_key(secure_key, secure_key_size)) { if (is_cca_aes_data_key(secure_key, secure_key_size)) { cca->dll_CSNBKTC(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, secure_key + AESDATA_KEY_SIZE); pr_verbose(verbose, "CSNBKTC (Key Token Change) with " "'%s' returned: return_code: %ld, " "reason_code: %ld", method, return_code, reason_code); } else if (is_cca_aes_cipher_key(secure_key, secure_key_size)) { cipherkey = (struct aescipherkeytoken *)(secure_key + AESCIPHER_KEY_SIZE); key_token_length = cipherkey->length; cca->dll_CSNBKTC2(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &key_token_length, (unsigned char *)cipherkey); pr_verbose(verbose, "CSNBKTC2 (Key Token Change2) with " "'%s' returned: return_code: %ld, " "reason_code: %ld", method, return_code, reason_code); pr_verbose(verbose, "key_token_length: %lu", key_token_length); } else { DEBUG("Invalid key type specified"); return -EINVAL; } if (return_code != 0) { print_CCA_error(return_code, reason_code); return -EIO; } } return 0; } /** * Queries the number of adapters known by the CCA host library * * @param[in] cca the CCA library structure * @param[out] adapters the number of adapters * @param[in] verbose if true, verbose messages are printed * * @returns 0 on success, a negative errno in case of an error. */ static int get_number_of_cca_adapters(struct cca_lib *cca, unsigned int *adapters, bool verbose) { long exit_data_len = 0, rule_array_count, verb_data_length = 0; unsigned char rule_array[16 * 8] = { 0, }; unsigned char exit_data[4] = { 0, }; long return_code, reason_code; util_assert(cca != NULL, "Internal error: cca is NULL"); util_assert(adapters != NULL, "Internal error: adapters is NULL"); if (cca->dll_CSUACFQ == NULL) { pr_verbose(verbose, "CCA host lib function CSUACFQ not " "available but required for getting number of CCA adapters."); return -ELIBACC; } memset(rule_array, 0, sizeof(rule_array)); memcpy(rule_array, "STATCRD2", 8); rule_array_count = 1; cca->dll_CSUACFQ(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &verb_data_length, NULL); pr_verbose(verbose, "CSUACFQ (Cryptographic Facility Query) returned: " "return_code: %ld, reason_code: %ld", return_code, reason_code); if (return_code != 0) { print_CCA_error(return_code, reason_code); return -EIO; } rule_array[8] = '\0'; if (sscanf((char *)rule_array, "%u", adapters) != 1) { pr_verbose(verbose, "Unparsable output: %s", rule_array); return -EIO; } pr_verbose(verbose, "Number of CCA adapters: %u", *adapters); return 0; } /** * Allocate a specific CCA adapter. * * @param[in] cca the CCA library structure * @param[in] adapter the adapter number, starting at 1. If 0 is * specified, then the AUTOSELECT option is * enabled. * @param[in] verbose if true, verbose messages are printed * * @returns 0 on success, a negative errno in case of an error. -ENODEV is * returned if the adapter is not available. */ static int allocate_cca_adapter(struct cca_lib *cca, unsigned int adapter, bool verbose) { long exit_data_len = 0, rule_array_count; unsigned char rule_array[8] = { 0, }; unsigned char exit_data[4] = { 0, }; long return_code, reason_code; char res_name[9]; long res_name_len; util_assert(cca != NULL, "Internal error: cca is NULL"); if (cca->dll_CSUACRA == NULL) { pr_verbose(verbose, "CCA host lib function CSUACRA not " "available but required for allocate CCA adapter."); return -ELIBACC; } if (adapter > 0) memcpy(rule_array, "DEVICE ", 8); else memcpy(rule_array, "DEV-ANY ", 8); rule_array_count = 1; sprintf(res_name, "CRP%02d", adapter); res_name_len = strlen(res_name); cca->dll_CSUACRA(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &res_name_len, (unsigned char *)res_name); pr_verbose(verbose, "CSUACRA (Cryptographic Resource Allocate) " "returned: return_code: %ld, reason_code: %ld", return_code, reason_code); if (return_code != 0) { print_CCA_error(return_code, reason_code); return -ENODEV; } pr_verbose(verbose, "Adapter %u (%s) allocated", adapter, res_name); return 0; } /** * Deallocate a specific CCA adapter. * * @param[in] cca the CCA library structure * @param[in] adapter the adapter number, starting at 1. If 0 is * specified, then the AUTOSELECT option is * disabled. * @param[in] verbose if true, verbose messages are printed * * @returns 0 on success, a negative errno in case of an error. -ENODEV is * returned if the adapter is not available. */ static int deallocate_cca_adapter(struct cca_lib *cca, unsigned int adapter, bool verbose) { long exit_data_len = 0, rule_array_count; unsigned char rule_array[8] = { 0, }; unsigned char exit_data[4] = { 0, }; long return_code, reason_code; char res_name[9]; long res_name_len; util_assert(cca != NULL, "Internal error: cca is NULL"); if (cca->dll_CSUACRD == NULL) { pr_verbose(verbose, "CCA host lib function CSUACRD not " "available but required for deallocate CCA adapter."); return -ELIBACC; } if (adapter > 0) memcpy(rule_array, "DEVICE ", 8); else memcpy(rule_array, "DEV-ANY ", 8); rule_array_count = 1; sprintf(res_name, "CRP%02d", adapter); res_name_len = strlen(res_name); cca->dll_CSUACRD(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &res_name_len, (unsigned char *)res_name); pr_verbose(verbose, "CSUACRD (Cryptographic Resource Deallocate) " "returned: return_code: %ld, reason_code: %ld", return_code, reason_code); if (return_code != 0) { print_CCA_error(return_code, reason_code); return -ENODEV; } pr_verbose(verbose, "Adapter %u (%s) deallocated", adapter, res_name); return 0; } /** * Queries the serial number of the current CCA adapter * * @param[in] cca the CCA library structure * @param[out] serialnr the buffer where the serial number is returned * @param[in] verbose if true, verbose messages are printed * * @returns 0 on success, a negative errno in case of an error. */ static int get_cca_adapter_serialnr(struct cca_lib *cca, char serialnr[9], bool verbose) { long exit_data_len = 0, rule_array_count, verb_data_length = 0; unsigned char rule_array[16 * 8] = { 0, }; unsigned char exit_data[4] = { 0, }; long return_code, reason_code; util_assert(cca != NULL, "Internal error: cca is NULL"); if (cca->dll_CSUACFQ == NULL) { pr_verbose(verbose, "CCA host lib function CSUACFQ not " "available but required for get adapter serialnr."); return -ELIBACC; } memset(rule_array, 0, sizeof(rule_array)); memcpy(rule_array, "STATCRD2", 8); rule_array_count = 1; cca->dll_CSUACFQ(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &verb_data_length, NULL); pr_verbose(verbose, "CSUACFQ (Cryptographic Facility Query) returned: " "return_code: %ld, reason_code: %ld", return_code, reason_code); if (return_code != 0) { print_CCA_error(return_code, reason_code); return -EIO; } memcpy(serialnr, rule_array+14*8, 8); serialnr[8] = '\0'; pr_verbose(verbose, "Serial number of CCA adapter: %s", serialnr); return 0; } /** * Selects the specified APQN to be used for the CCA host library. * * @param[in] cca the CCA library structure * @param[in] card the card number * @param[in] domain the domain number * @param[in] verbose if true, verbose messages are printed * * @returns 0 on success, a negative errno in case of an error. -ENOTSUP is * returned when the serialnr sysfs attribute is not available, * because the zcrypt kernel module is on an older level. -ENODEV is * returned if the APQN is not available. */ int select_cca_adapter(struct cca_lib *cca, unsigned int card, unsigned int domain, bool verbose) { unsigned int adapters, adapter; char adapter_serialnr[9]; char apqn_serialnr[SERIALNR_LENGTH]; char temp[10]; int rc, found = 0; util_assert(cca != NULL, "Internal error: cca is NULL"); pr_verbose(verbose, "Select %02x.%04x for the CCA host library", card, domain); rc = sysfs_get_serialnr(card, apqn_serialnr, verbose); if (rc != 0) { pr_verbose(verbose, "Failed to get the serial number: %s", strerror(-rc)); return rc; } sprintf(temp, "%u", domain); if (setenv(CCA_DOMAIN_ENVAR, temp, 1) != 0) { rc = -errno; pr_verbose(verbose, "Failed to set the %s environment variable:" " %s", CCA_DOMAIN_ENVAR, strerror(-rc)); return rc; } unsetenv(CCA_ADAPTER_ENVAR); /* * Unload and reload the CCA host library so that it recognizes the * changed CSU_DEFAULT_DOMAIN environment variable value. */ if (cca->lib_csulcca != NULL) dlclose(cca->lib_csulcca); memset(cca, 0, sizeof(struct cca_lib)); rc = load_cca_library(cca, verbose); if (rc != 0) return rc; rc = get_number_of_cca_adapters(cca, &adapters, verbose); if (rc != 0) return rc; /* Deallocate any adapter first, in case one is already allocated */ for (adapter = 1; adapter <= adapters; adapter++) deallocate_cca_adapter(cca, adapter, false); /* Disable the AUTOSELECT option */ rc = deallocate_cca_adapter(cca, 0, verbose); if (rc != 0) return rc; for (adapter = 1; adapter <= adapters; adapter++) { rc = allocate_cca_adapter(cca, adapter, verbose); if (rc != 0) return rc; rc = get_cca_adapter_serialnr(cca, adapter_serialnr, verbose); if (rc == 0) { if (memcmp(apqn_serialnr, adapter_serialnr, 8) == 0) { found = 1; break; } } rc = deallocate_cca_adapter(cca, adapter, verbose); if (rc != 0) return rc; } if (!found) return -ENODEV; pr_verbose(verbose, "Selected adapter %u (CRP%02d)", adapter, adapter); return 0; } /** * Setup rule array for key token build: * defaults: * - XPRTCPAC : make the secure key CPACF exportable * - KEY-MGMT : digital signature generate (prime curves) * - SIG-ONLY : digital signature generate (edwards curves) * via flags: * - AES1ECOK : allow export using an AES key of similar strength */ void setup_rule_array(int curve, unsigned int flags, uint8_t *rule_array_buf, long *rule_array_count) { memcpy(rule_array_buf, "ECC-PAIR", CCA_KEYWORD_SIZE); *rule_array_count = 1; memcpy(rule_array_buf + *rule_array_count * CCA_KEYWORD_SIZE, "XPRTCPAC", CCA_KEYWORD_SIZE); (*rule_array_count)++; switch (curve2ccatype[curve]) { case CCA_EC_CURVE_TYPE_PRIME: memcpy(rule_array_buf + *rule_array_count * CCA_KEYWORD_SIZE, "KEY-MGMT", CCA_KEYWORD_SIZE); break; case CCA_EC_CURVE_TYPE_EDWARDS: memcpy(rule_array_buf + *rule_array_count * CCA_KEYWORD_SIZE, "SIG-ONLY", CCA_KEYWORD_SIZE); break; } (*rule_array_count)++; /* Add user-defined flags: the only flag that is currently recognized here, * is PKEY_KEYGEN_XPRT_AES : Allow export using an AES key. */ if ((flags & PKEY_KEYGEN_XPRT_AES) == PKEY_KEYGEN_XPRT_AES) { memcpy(rule_array_buf + *rule_array_count * CCA_KEYWORD_SIZE, "AES1ECOK", CCA_KEYWORD_SIZE); (*rule_array_count)++; } } /** * Setup key value structure for key token build. */ void setup_key_value_struct(uint8_t *kvs_buf, long *kvs_len, int curve, const unsigned char *pubkey, unsigned int publen, const unsigned char *privkey, unsigned int privlen) { ECC_PAIR ecc_pair; ecc_pair.curve_type = curve2ccatype[curve]; ecc_pair.reserved = 0x00; ecc_pair.p_bitlen = curve2bitlen[curve]; ecc_pair.d_length = privlen; ecc_pair.q_length = publen; memcpy(kvs_buf, &ecc_pair, sizeof(ECC_PAIR)); if (privlen > 0) memcpy(kvs_buf + sizeof(ECC_PAIR), privkey, privlen); *kvs_len = sizeof(ECC_PAIR) + privlen; if (publen > 0) { if (curve2ccatype[curve] == CCA_EC_CURVE_TYPE_PRIME) { memset(kvs_buf + sizeof(ECC_PAIR) + privlen, 0x04, 1); memcpy(kvs_buf + sizeof(ECC_PAIR) + privlen + 1, pubkey, publen); ecc_pair.q_length = publen + 1; *kvs_len = *kvs_len + 1 + publen; } else { /* Edwards curves do not have a compression indication in the kvs struct */ memcpy(kvs_buf + sizeof(ECC_PAIR) + privlen, pubkey, publen); *kvs_len = *kvs_len + publen; } } } int ec_key_generate_cca(struct cca_lib *cca, int curve, unsigned int flags, unsigned char *secure_key, unsigned int *seclen, unsigned char *public_key, unsigned int *publen, bool verbose) { unsigned char kvs_buf[CCA_EC_KEY_VALUE_STRUCT_SIZE] = { 0 }; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0 }; unsigned char skel_token[CCA_KEY_TOKEN_SIZE] = { 0 }; unsigned char trans_key[CCA_TRANSPORT_KEY_SIZE] = { 0 }; unsigned char ecc_token[CCA_KEY_TOKEN_SIZE] = { 0 }; unsigned char exit_data[4] = { 0 }; unsigned char buf[132] = { 0 }; long skel_token_len = sizeof(skel_token); long ecc_token_len = sizeof(ecc_token); long regen_data_len = 0, kvs_len = 0, exit_data_len = 0; long return_code = 0, reason_code = 0, key_name_len = 0; long rlen1 = 0, rlen2 = 0, rlen3 = 0, rlen4 = 0, rlen5 = 0; long rule_array_count = 0; unsigned int buflen = sizeof(buf); int rc; if (cca->dll_CSNDPKB == NULL || cca->dll_CSNDPKG == NULL) { pr_verbose(verbose, "CCA host lib function CSNDPKB and/or CSNDPKG not " "available but required for EC key generate."); return -ELIBACC; } *seclen = 0; *publen = 0; /* Create skeleton token */ setup_rule_array(curve, flags, rule_array, &rule_array_count); setup_key_value_struct(kvs_buf, &kvs_len, curve, NULL, 0, NULL, 0); cca->dll_CSNDPKB(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &kvs_len, kvs_buf, &key_name_len, NULL, &rlen1, NULL, &rlen2, NULL, &rlen3, NULL, &rlen4, NULL, &rlen5, NULL, &skel_token_len, skel_token); pr_verbose(verbose, "CSNDPKB (PKA Key Token Build) " "returned: return_code: %ld, reason_code: %ld", return_code, reason_code); if (return_code != 0) { print_CCA_error(return_code, reason_code); return -EIO; } /* Generate secure key token */ memcpy(rule_array, "MASTER ", CCA_KEYWORD_SIZE); rule_array_count = 1; cca->dll_CSNDPKG(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, ®en_data_len, NULL, &skel_token_len, skel_token, trans_key, &ecc_token_len, (unsigned char *)&ecc_token); pr_verbose(verbose, "CSNDPKG (PKA Key Generate) " "returned: return_code: %ld, reason_code: %ld", return_code, reason_code); if (return_code != 0) { print_CCA_error(return_code, reason_code); return -EIO; } memcpy(secure_key, ecc_token, ecc_token_len); *seclen = ecc_token_len; /* Extract public key from secure key token */ rc = ec_key_extract_public_cca(cca, ecc_token, ecc_token_len, (unsigned char *)&buf, &buflen, verbose); if (rc == 0 && buflen > 0) { memcpy(public_key, buf, buflen); *publen = buflen; } return 0; } /** * Extract the public key out if the given secure key blob. A public key can * only be obtained, if it is already contained in the token. The host lib * does not re-calculate the public key from the given private key. */ int ec_key_extract_public_cca(struct cca_lib *cca, unsigned char *ecc_token, unsigned int ecc_token_len, unsigned char *ecc_pub_token, unsigned int *p_ecc_pub_token_len, bool verbose) { unsigned char rule_array_buf[CCA_RULE_ARRAY_SIZE] = { 0 }; unsigned char buf[CCA_EC_KEY_VALUE_STRUCT_SIZE] = { 0 }; unsigned char exit_data[4]; long return_code = 0, reason_code = 0, exit_data_len = 0; long rule_array_count = 0; long buflen = sizeof(buf); struct eccpubtoken *pubtok; if (cca->dll_CSNDPKX == NULL) { pr_verbose(verbose, "CCA host lib function CSNDPKX not " "available but required for public key extract."); return -ELIBACC; } /* Extract the public key from secure key token */ cca->dll_CSNDPKX(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array_buf, (long *)&ecc_token_len, ecc_token, &buflen, (unsigned char *)&buf); pr_verbose(verbose, "CSNDPKX (PKA Public Key Extract) " "returned: return_code: %ld, reason_code: %ld", return_code, reason_code); if (return_code != 0) { print_CCA_error(return_code, reason_code); return -EIO; } /* Copy result: public token comes after the CCA header */ pubtok = (struct eccpubtoken *)&buf[CCA_EC_HEADER_SIZE]; if (pubtok->curve_type == CCA_EC_CURVE_TYPE_PRIME) { /* Remove indication for uncompressed key 0x04 */ memcpy(ecc_pub_token, pubtok->q + 1, pubtok->q_len - 1); *p_ecc_pub_token_len = pubtok->q_len - 1; } else { memcpy(ecc_pub_token, pubtok->q, pubtok->q_len); *p_ecc_pub_token_len = pubtok->q_len; } return 0; } int ec_key_clr2sec_cca(struct cca_lib *cca, int curve, unsigned int flags, unsigned char *secure_key, unsigned int *seclen, const unsigned char *pubkey, unsigned int publen, const unsigned char *privkey, unsigned int privlen, bool verbose) { unsigned char private_key_name[CCA_PRIVATE_KEY_NAME_SIZE] = { 0, }; unsigned char rule_array[CCA_RULE_ARRAY_SIZE] = { 0, }; unsigned char transport_key_identifier[CCA_KEY_ID_SIZE] = { 0, }; unsigned char target_key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; unsigned char kvs_buf[CCA_EC_KEY_VALUE_STRUCT_SIZE] = { 0, }; unsigned char key_token[CCA_KEY_TOKEN_SIZE] = { 0, }; unsigned char *exit_data = NULL, *param2 = NULL; long return_code = 0, reason_code = 0, rule_array_count = 0; long exit_data_len = 0, kvs_len = 0, private_key_name_length = 0; long key_token_length = CCA_KEY_TOKEN_SIZE; long param1 = 0, target_key_token_length = 0; if (cca->dll_CSNDPKB == NULL || cca->dll_CSNDPKI == NULL) { pr_verbose(verbose, "CCA host lib function CSNDPKB and/or CSNDPKI not " "available but required for clear key import."); return -ELIBACC; } setup_key_value_struct(kvs_buf, &kvs_len, curve, pubkey, publen, privkey, privlen); setup_rule_array(curve, flags, rule_array, &rule_array_count); cca->dll_CSNDPKB(&return_code, &reason_code, &exit_data_len, exit_data, &rule_array_count, rule_array, &kvs_len, kvs_buf, &private_key_name_length, private_key_name, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, ¶m1, param2, &key_token_length, key_token); pr_verbose(verbose, "CSNDPKB (PKA Key Token Build) " "returned: return_code: %ld, reason_code: %ld", return_code, reason_code); if (return_code != 0) { print_CCA_error(return_code, reason_code); return -EIO; } /* Now import the PKA key token */ memcpy(rule_array, "ECC ", CCA_KEYWORD_SIZE); rule_array_count = 1; key_token_length = CCA_KEY_TOKEN_SIZE; target_key_token_length = CCA_KEY_TOKEN_SIZE; cca->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); pr_verbose(verbose, "CSNDPKI (PKA Key Import) " "returned: return_code: %ld, reason_code: %ld", return_code, reason_code); if (return_code != 0) { print_CCA_error(return_code, reason_code); return -EIO; } memcpy(secure_key, target_key_token, target_key_token_length); *seclen = target_key_token_length; return 0; } libzpc-1.3.0/src/zkey/cca.h000066400000000000000000000205331475140344100154540ustar00rootroot00000000000000/* * zkey - Generate, re-encipher, and validate secure keys * * This header file defines the interface to the CCA host library. * * Copyright IBM Corp. 2019 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef CCA_H #define CCA_H #include #include "lib/zt_common.h" /* CCA library constants */ #define CCA_PRIVATE_KEY_NAME_SIZE 64 #define CCA_KEY_TOKEN_SIZE 3500 #define CCA_TRANSPORT_KEY_SIZE 1024 #define CCA_EC_KEY_VALUE_STRUCT_SIZE 207 #define CCA_KEYWORD_SIZE 8 #define CCA_RULE_ARRAY_SIZE 256 #define CCA_KEY_ID_SIZE 64 #define CCA_EC_HEADER_SIZE 8 #define CCA_EC_CURVE_TYPE_PRIME 0 #define CCA_EC_CURVE_TYPE_EDWARDS 2 #define METHOD_OLD_TO_CURRENT "RTCMK " #define METHOD_CURRENT_TO_NEW "RTNMK " /* * General format of a variable-length symmetric key-token, version X'05'. * Optional key-management field 1, high-order byte (export control): * (Refer to kernel's zcrypt_cca_misc.h) */ typedef enum { KMF1_XPRT_CPAC = 0x0800, } AES_Key_Flags; /* * ECC private key section (X'20'), Key-usage and translation control flag. */ typedef enum { CCA_XPRTCPAC = 0x01, } ECC_Key_Flags; typedef void (*t_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); typedef void (*t_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); typedef void (*t_CSUACFV)(long *return_code, long *reason_code, long *exit_data_length, unsigned char *exit_data, long *version_data_length, unsigned char *version_data); typedef void (*t_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); typedef void (*t_CSUACRA)(long *return_code, long *reason_code, long *exit_data_length, unsigned char *exit_data, long *rule_array_count, unsigned char *rule_array, long *ressource_name_length, unsigned char *ressource_name); typedef void (*t_CSUACRD)(long *return_code, long *reason_code, long *exit_data_length, unsigned char *exit_data, long *rule_array_count, unsigned char *rule_array, long *ressource_name_length, unsigned char *ressource_name); typedef void (*t_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 *verb_data_length, unsigned char *verb_data, long *target_key_token_length, unsigned char *target_key_token); typedef void (*t_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); typedef void (*t_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 *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); typedef void (*t_CSNDPKB) (long *return_code, long *reason_code, long *exit_data_length, unsigned char *exit_data, long *rule_array_count, unsigned char *rule_array, long *kvs_len, unsigned char *kvs, long *key_name_len, unsigned char *key_name, long *rlen1, unsigned char *r1, long *rlen2, unsigned char *r2, long *rlen3, unsigned char *r3, long *rlen4, unsigned char *r4, long *rlen5, unsigned char *r5, long *skel_token_len, unsigned char *skel_token); typedef void (*t_CSNDPKG) (long *return_code, long *reason_code, long *exit_data_length, unsigned char *exit_data, long *rule_array_count, unsigned char *rule_array, long *regen_data_len, unsigned char *regen_data, long *skel_token_len, unsigned char *kel_token, unsigned char *trans_key, long *ecc_token_len, unsigned char *sec_key); typedef void (*t_CSNDPKX) (long *return_code, long *reason_code, long *exit_data_length, unsigned char *exit_data, long *rule_array_count, unsigned char *rule_array, long *ecc_token_len, unsigned char *ecc_token, long *ecc_pub_token_len, unsigned char *ecc_pub_token); typedef void (*t_CSNDPKI) (long *return_code, long *reason_code, long *exit_data_length, unsigned char *exit_data, long *rule_array_count, unsigned char *rule_array, long *key_token_length, unsigned char *key_token, unsigned char *transport_key_identifier, long *target_key_token_length, unsigned char *target_key_token); typedef void (*t_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_identifier_length, unsigned char *key_identifier); struct cca_version { unsigned int ver; unsigned int rel; unsigned int mod; }; struct cca_lib { void *lib_csulcca; t_CSNBKTC dll_CSNBKTC; t_CSNBKTC2 dll_CSNBKTC2; t_CSUACFV dll_CSUACFV; t_CSUACFQ dll_CSUACFQ; t_CSUACRA dll_CSUACRA; t_CSUACRD dll_CSUACRD; t_CSNBKTB2 dll_CSNBKTB2; t_CSNBKTR2 dll_CSNBKTR2; t_CSNBRKA dll_CSNBRKA; t_CSNDPKB dll_CSNDPKB; t_CSNDPKG dll_CSNDPKG; t_CSNDPKX dll_CSNDPKX; t_CSNDPKI dll_CSNDPKI; t_CSNDKTC dll_CSNDKTC; struct cca_version version; }; /* * Refer to CCA Programmer's Guide, PKA Key Token Build * Key value structure elements, ECC keys */ typedef struct { u8 curve_type; /* 00 = prime, 02 = edwards */ u8 reserved; u16 p_bitlen; u16 d_length; u16 q_length; // followed by d || q }__attribute__((packed)) ECC_PAIR; int load_cca_library(struct cca_lib *cca, bool verbose); int key_token_change(struct cca_lib *cca, u8 *secure_key, unsigned int secure_key_size, char *method, bool verbose); int select_cca_adapter(struct cca_lib *cca, unsigned int card, unsigned int domain, bool verbose); #define FLAG_SEL_CCA_MATCH_CUR_MKVP 0x01 #define FLAG_SEL_CCA_MATCH_OLD_MKVP 0x02 #define FLAG_SEL_CCA_NEW_MUST_BE_SET 0x80 int select_cca_adapter_by_mkvp(struct cca_lib *cca, u8 *mkvp, const char *apqns, unsigned int flags, bool verbose); void print_msg_for_cca_envvars(const char *key_name); int convert_aes_data_to_cipher_key(struct cca_lib *cca, u8 *input_key, unsigned int input_key_size, u8 *output_key, unsigned int *output_key_size, bool verbose); int restrict_key_export(struct cca_lib *cca, u8 *secure_key, unsigned int secure_key_size, bool verbose); int ec_key_generate_cca(struct cca_lib *cca, int curve, unsigned int flags, unsigned char *secure_key, unsigned int *seclen, unsigned char *public_key, unsigned int *publen, bool verbose); int ec_key_extract_public_cca(struct cca_lib *cca, unsigned char *ecc_token, unsigned int ecc_token_len, unsigned char *ecc_pub_token, unsigned int *p_ecc_pub_token_len, bool verbose); int ec_key_clr2sec_cca(struct cca_lib *cca, int curve, unsigned int flags, unsigned char *secure_key, unsigned int *seclen, const unsigned char *pubkey, unsigned int publen, const unsigned char *privkey, unsigned int privlen, bool verbose); #endif libzpc-1.3.0/src/zkey/ep11.c000066400000000000000000000767471475140344100155110ustar00rootroot00000000000000/* * zkey - Generate, re-encipher, and validate secure keys * * Copyright IBM Corp. 2019 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include #include #include #include #include #include #include #include #include "lib/util_base.h" #include "lib/util_libc.h" #include "lib/util_panic.h" #include "ep11.h" #include "pkey.h" #include "utils.h" #include "debug.h" #define pr_verbose(verbose, fmt...) do { \ if (verbose) \ DEBUG(fmt); \ } while (0) /* * Definitions for the EP11 library */ #define EP11_LIBRARY_NAME "libep11.so" #define EP11_LIBRARY_VERSION 4 #define EP11_WEB_PAGE "http://www.ibm.com/security/cryptocards" extern const size_t curve2publen[]; extern const uint16_t curve2bitlen[]; extern const size_t curve2puboffset[]; extern const size_t curve2macedspkilen[]; /* * Some SPKI related constants */ const unsigned char p256_spki_seq1[] = ZPC_P256_SPKI_SEQ1; const unsigned char p384_spki_seq1[] = ZPC_P384_SPKI_SEQ1; const unsigned char p521_spki_seq1[] = ZPC_P521_SPKI_SEQ1; const unsigned char ed25519_spki_seq1[] = ZPC_ED25519_SPKI_SEQ1; const unsigned char ed448_spki_seq1[] = ZPC_ED448_SPKI_SEQ1; const unsigned char *curve2spki_seq1[] = { (unsigned char *)&p256_spki_seq1, (unsigned char *)&p384_spki_seq1, (unsigned char *)&p521_spki_seq1, (unsigned char *)&ed25519_spki_seq1, (unsigned char *)&ed448_spki_seq1, }; const size_t curve2spki_seq1_len[] = { sizeof(p256_spki_seq1), sizeof(p384_spki_seq1), sizeof(p521_spki_seq1), sizeof(ed25519_spki_seq1), sizeof(ed448_spki_seq1), }; const unsigned char ec_pubkey[] = ZPC_EC_PUBKEY; const size_t ec_pubkey_len = sizeof(ec_pubkey); const unsigned char p256_params[] = ZPC_P256_PARAMS; const unsigned char p384_params[] = ZPC_P384_PARAMS; const unsigned char p521_params[] = ZPC_P521_PARAMS; const unsigned char ed25519_params[] = ZPC_ED25519_PARAMS; const unsigned char ed448_params[] = ZPC_ED448_PARAMS; const unsigned char *curve2spki_ec_params[] = { (unsigned char *)&p256_params, (unsigned char *)&p384_params, (unsigned char *)&p521_params, (unsigned char *)&ed25519_params, (unsigned char *)&ed448_params, }; const size_t curve2spki_ec_params_len[] = { sizeof(p256_params), sizeof(p384_params), sizeof(p521_params), sizeof(ed25519_params), sizeof(ed448_params), }; /** * Returns the major and minor version of the of the used EP11 host library. * * @param[in] ep11 the EP11 library structure * @param[in] verbose if true, verbose messages are printed * * @returns 0 on success, a negative errno in case of an error */ static int get_ep11_version(struct ep11_lib *ep11, bool verbose) { unsigned int host_version; CK_ULONG version_len = sizeof(host_version); CK_RV rc; if (ep11->lib_ep11 == NULL) return -ELIBACC; if (ep11->dll_m_get_xcp_info == NULL) { pr_verbose(verbose, "EP11 host lib function m_get_xcp_info not " "available but required for getting the EP11 library version."); return -ELIBACC; } rc = ep11->dll_m_get_xcp_info(&host_version, &version_len, CK_IBM_XCPHQ_VERSION, 0, 0); if (rc != CKR_OK) { pr_verbose(verbose, "Failed to obtain the EP11 host library " "version: m_get_xcp_info: 0x%lx", rc); return -EIO; } pr_verbose(verbose, "host_version: 0x%08x", host_version); ep11->version.major = (host_version & 0x00FF0000) >> 16; ep11->version.minor = (host_version & 0x0000FF00) >> 8; ep11->version.modification = host_version & 0x000000FF; /* * EP11 host library < v2.0 returns an invalid version (i.e. 0x100). * This can safely be treated as version 1.0 */ if (ep11->version.major == 0) { ep11->version.major = 1; ep11->version.minor = 0; } pr_verbose(verbose, "EP11 library version: %u.%u.%u", ep11->version.major, ep11->version.minor, ep11->version.modification); return 0; } /** * Loads the EP11 library and provides the entry points of several functions. * * @param[out] ep11 on return this contains the address of the EP11 * library and certain EP11 symbols. dlclose() should * be used to free the library when no longer needed. * @param verbose if true, verbose messages are printed * * @returns 0 on success, -ELIBACC in case of library load errors */ int load_ep11_library(struct ep11_lib *ep11, bool verbose) { char lib_name[256]; int libver; int all_entry_points_loaded = 1, rc; util_assert(ep11 != NULL, "Internal error: ep11 is NULL"); /* Load the EP11 library with highest available version'd SO name */ for (libver = EP11_LIBRARY_VERSION; libver >= 0; libver--) { if (libver > 0) sprintf(lib_name, "%s.%d", EP11_LIBRARY_NAME, libver); else sprintf(lib_name, "%s", EP11_LIBRARY_NAME); ep11->lib_ep11 = dlopen(lib_name, RTLD_GLOBAL | RTLD_NOW); if (ep11->lib_ep11 != NULL) break; } if (ep11->lib_ep11 == NULL) { pr_verbose(verbose, "%s", dlerror()); DEBUG("The command requires the IBM Z Enterprise PKCS #11 " "(EP11) Support Program (EP11 host library).\n" "For the supported environments and downloads, see:\n%s", EP11_WEB_PAGE); return -ELIBACC; } /* Get several EP11 host library functions */ ep11->dll_m_init = (m_init_t)dlsym(ep11->lib_ep11, "m_init"); ep11->dll_m_add_module = (m_add_module_t)dlsym(ep11->lib_ep11, "m_add_module"); ep11->dll_m_rm_module = (m_rm_module_t)dlsym(ep11->lib_ep11, "m_rm_module"); ep11->dll_m_get_xcp_info = (m_get_xcp_info_t)dlsym(ep11->lib_ep11, "m_get_xcp_info"); ep11->dll_m_admin = (m_admin_t)dlsym(ep11->lib_ep11, "m_admin"); ep11->dll_xcpa_cmdblock = (xcpa_cmdblock_t)dlsym(ep11->lib_ep11, "xcpa_cmdblock"); if (ep11->dll_xcpa_cmdblock == NULL) ep11->dll_xcpa_cmdblock = (xcpa_cmdblock_t)dlsym(ep11->lib_ep11, "ep11a_cmdblock"); ep11->dll_xcpa_internal_rv = (xcpa_internal_rv_t)dlsym(ep11->lib_ep11, "xcpa_internal_rv"); if (ep11->dll_xcpa_internal_rv == NULL) ep11->dll_xcpa_internal_rv = (xcpa_internal_rv_t)dlsym(ep11->lib_ep11, "ep11a_internal_rv"); ep11->dll_m_UnwrapKey = (m_UnwrapKey_t)dlsym(ep11->lib_ep11, "m_UnwrapKey"); ep11->dll_m_EncryptSingle = (m_EncryptSingle_t)dlsym(ep11->lib_ep11, "m_EncryptSingle"); ep11->dll_m_GenerateKeyPair = (m_GenerateKeyPair_t)dlsym(ep11->lib_ep11, "m_GenerateKeyPair"); ep11->dll_m_GenerateKey = (m_GenerateKey_t)dlsym(ep11->lib_ep11, "m_GenerateKey"); ep11->dll_m_GetAttributeValue = (m_GetAttributeValue_t)dlsym(ep11->lib_ep11, "m_GetAttributeValue"); /* dll_m_add_module and dll_m_rm_module may be NULL for V1 EP11 lib */ if (ep11->dll_m_init == NULL || ep11->dll_m_get_xcp_info == NULL || ep11->dll_m_admin == NULL || ep11->dll_xcpa_cmdblock == NULL || ep11->dll_xcpa_internal_rv == NULL || ep11->dll_m_UnwrapKey == NULL || ep11->dll_m_EncryptSingle == NULL || ep11->dll_m_GenerateKeyPair == NULL || ep11->dll_m_GenerateKey == NULL || ep11->dll_m_GetAttributeValue == NULL) { pr_verbose(verbose, "%s", dlerror()); DEBUG("The command requires the IBM Z Enterprise PKCS #11 " "(EP11) Support Program (EP11 host library).\n" "For the supported environments and downloads, see:\n%s", EP11_WEB_PAGE); all_entry_points_loaded = 0; } if (ep11->dll_m_init == NULL) { dlclose(ep11->lib_ep11); ep11->lib_ep11 = NULL; return -ELIBACC; } /* Initialize the EP11 library */ rc = ep11->dll_m_init(); if (rc != 0) { pr_verbose(verbose, "Failed to initialize the EP11 host " "library: m_init: 0x%x", rc); dlclose(ep11->lib_ep11); ep11->lib_ep11 = NULL; return -ELIBACC; } if (all_entry_points_loaded) pr_verbose(verbose, "EP11 library '%s' has been loaded successfully, " "all expected entry points available.", lib_name); else pr_verbose(verbose, "EP11 library '%s' has been loaded successfully, " "but some entry points are missing.", lib_name); return get_ep11_version(ep11, verbose); } /** * Get an EP11 target handle for a specific APQN (card and domain) * * @param[in] ep11 the EP11 library structure * @param[in] card the card number * @param[in] domain the domain number * @param[out] target on return: the target handle for the APQN * @param verbose if true, verbose messages are printed * * @returns 0 on success, a negative errno in case of errors */ int get_ep11_target_for_apqn(struct ep11_lib *ep11, unsigned int card, unsigned int domain, target_t *target, bool verbose) { ep11_target_t *target_list; struct XCP_Module module; CK_RV rc; util_assert(ep11 != NULL, "Internal error: ep11 is NULL"); util_assert(target != NULL, "Internal error: target is NULL"); *target = XCP_TGT_INIT; if (ep11->dll_m_add_module != NULL) { memset(&module, 0, sizeof(module)); module.version = ep11->version.major >= 3 ? XCP_MOD_VERSION_2 : XCP_MOD_VERSION_1; module.flags = XCP_MFL_MODULE; module.module_nr = card; XCPTGTMASK_SET_DOM(module.domainmask, domain); rc = ep11->dll_m_add_module(&module, target); if (rc != 0) { pr_verbose(verbose, "Failed to add APQN %02x.%04x: " "m_add_module rc=0x%lx", card, domain, rc); return -EIO; } } else { /* Fall back to old target handling */ target_list = (ep11_target_t *)calloc(1, sizeof(ep11_target_t)); if (target_list == NULL) return -ENOMEM; target_list->length = 1; target_list->apqns[0] = card; target_list->apqns[1] = domain; *target = (target_t)target_list; } return 0; } /** * Free an EP11 target handle * * @param[in] ep11 the EP11 library structure * @param[in] target the target handle to free * * @returns 0 on success, a negative errno in case of errors */ void free_ep11_target_for_apqn(struct ep11_lib *ep11, target_t target) { util_assert(ep11 != NULL, "Internal error: ep11 is NULL"); if (ep11->dll_m_rm_module != NULL) { ep11->dll_m_rm_module(NULL, target); } else { /* * With the old target handling, target is a pointer to * ep11_target_t */ free((ep11_target_t *)target); } } /** * Performs an EP11 administrative request to Re-encrypt a single EP11 secure * key with a new EP11 master key (wrapping key). * * @param[in] ep11 the EP11 library structure * @param[in] target the target handle to use for the re-encipher operation * @param[in] card the card that corresponds to the target handle * @param[in] domain the domain that corresponds to the target handle * @param[in/out] ep11key the EP11 key token to reencipher. The re-enciphered * secure key will be returned in this buffer. * @param[in] ep11key_size the size of the secure key * @param[in] verbose if true, verbose messages are printed * * @returns 0 on success, a negative errno in case of errors */ static int ep11_adm_reencrypt(struct ep11_lib *ep11, target_t target, unsigned int card, unsigned int domain, struct ep11keytoken *ep11key, unsigned int ep11key_size, bool verbose) { CK_BYTE resp[MAX_BLOBSIZE]; CK_BYTE req[MAX_BLOBSIZE]; struct XCPadmresp lrb; struct XCPadmresp rb; size_t resp_len; size_t blob_len; long req_len; CK_RV rv; int rc; if (ep11->dll_xcpa_cmdblock == NULL) { pr_verbose(verbose, "EP11 host lib function xcpa_cmdblock not " "available but required for EP11 adm reencrypt."); return -ELIBACC; } blob_len = ep11key_size; rb.domain = domain; lrb.domain = domain; resp_len = sizeof(resp); req_len = ep11->dll_xcpa_cmdblock(req, sizeof(req), XCP_ADM_REENCRYPT, &rb, NULL, (unsigned char *)ep11key, blob_len); if (req_len < 0) { pr_verbose(verbose, "Failed to build XCP command block"); return -EIO; } rv = ep11->dll_m_admin(resp, &resp_len, NULL, NULL, req, req_len, NULL, 0, target); if (rv != CKR_OK || resp_len == 0) { pr_verbose(verbose, "Command XCP_ADM_REENCRYPT failed. " "rc = 0x%lx, resp_len = %ld", rv, resp_len); return -EIO; } rc = ep11->dll_xcpa_internal_rv(resp, resp_len, &lrb, &rv); if (rc != 0) { pr_verbose(verbose, "Failed to parse response. rc = %d", rc); return -EIO; } if (rv != CKR_OK) { pr_verbose(verbose, "Failed to re-encrypt the EP11 secure key. " "rc = 0x%lx", rv); switch (rv) { case CKR_IBM_WKID_MISMATCH: DEBUG("The EP11 secure key is currently encrypted " "under a different master that does not match " "the master key in the CURRENT master key " "register of APQN %02X.%04X", card, domain); break; } return -EIO; } if (blob_len != lrb.pllen) { pr_verbose(verbose, "Re-encrypted EP11 secure key size has " "changed: org-len: %lu, new-len: %lu", blob_len, lrb.pllen); return -EIO; } memcpy(ep11key, lrb.payload, blob_len); return 0; } /** * Re-encipher an EP11 secure key with a new EP11 master key (wrapping key). * * @param[in] ep11 the EP11 library structure * @param[in] target the target handle to use for the re-encipher operation * @param[in] card the card that corresponds to the target handle * @param[in] domain the domain that corresponds to the target handle * @param[in/out] secure_key the EP11 key token to reencipher. The re-enciphered * secure key will be returned in this buffer. * @param[in] secure_key_size the size of the secure key * @param[in] verbose if true, verbose messages are printed * * @returns 0 on success, a negative errno in case of errors */ int reencipher_ep11_key(struct ep11_lib *ep11, target_t target, unsigned int card, unsigned int domain, u8 *secure_key, unsigned int secure_key_size, bool verbose) { struct ep11keytoken *ep11key = (struct ep11keytoken *)secure_key; CK_IBM_DOMAIN_INFO dinf; CK_ULONG dinf_len = sizeof(dinf); CK_RV rv; int rc; util_assert(ep11 != NULL, "Internal error: ep11 is NULL"); util_assert(secure_key != NULL, "Internal error: secure_key is NULL"); if (ep11->dll_m_get_xcp_info == NULL) { pr_verbose(verbose, "EP11 host lib function m_get_xcp_info not " "available but required for EP11 EC key reencipher."); return -ELIBACC; } rv = ep11->dll_m_get_xcp_info(&dinf, &dinf_len, CK_IBM_XCPQ_DOMAIN, 0, target); if (rv != CKR_OK) { pr_verbose(verbose, "Failed to query domain information for " "%02X.%04X: m_get_xcp_info rc: 0x%lx", card, domain, rv); return -EIO; } if ((dinf.flags & CK_IBM_DOM_COMMITTED_NWK) == 0) { DEBUG("The NEW master key register of APQN %02X.%04X is not " "in COMMITTED state", card, domain); return -ENODEV; } rc = ep11_adm_reencrypt(ep11, target, card, domain, ep11key, secure_key_size, verbose); if (rc != 0) return rc; if (is_xts_key(secure_key, secure_key_size)) { secure_key += EP11_KEY_SIZE; secure_key_size -= EP11_KEY_SIZE; ep11key = (struct ep11keytoken *)secure_key; rc = ep11_adm_reencrypt(ep11, target, card, domain, ep11key, secure_key_size, verbose); if (rc != 0) return rc; } return 0; } /* * For importing keys we need to encrypt the keys. So build the blob by * m_UnwrapKey, use one wrap key for this purpose, can be any key, * we use an AES key */ CK_RV make_wrapblob(struct ep11_lib *ep11, target_t target) { CK_MECHANISM mech = { CKM_AES_KEY_GEN, NULL, 0 }; CK_BYTE csum[MAX_CSUMSIZE]; size_t csum_len = sizeof(csum); CK_RV rv = 0; CK_BBOOL cktrue = CK_TRUE; CK_ULONG len = 32; CK_ATTRIBUTE wrap_tmpl[] = { { CKA_VALUE_LEN, &len, sizeof(CK_ULONG) }, { CKA_WRAP, (void *) &cktrue, sizeof(cktrue) }, { CKA_UNWRAP, (void *) &cktrue, sizeof(cktrue) }, }; CK_ULONG wrap_tmpl_len = sizeof(wrap_tmpl) / sizeof(CK_ATTRIBUTE); if (ep11->dll_m_GenerateKey == NULL) { DEBUG("EP11 host lib function m_GenerateKey not available but " "required for creating the EP11 wrap blob."); return CKR_FUNCTION_NOT_SUPPORTED; } if (ep11->raw2key_wrap_blob_l != 0) return CKR_OK; ep11->raw2key_wrap_blob_l = sizeof(ep11->raw2key_wrap_blob); rv = ep11->dll_m_GenerateKey(&mech, wrap_tmpl, wrap_tmpl_len, NULL, 0, ep11->raw2key_wrap_blob, &ep11->raw2key_wrap_blob_l, csum, &csum_len, target); if (rv != CKR_OK) { ep11->raw2key_wrap_blob_l = 0; goto ret; } rv = CKR_OK; ret: return rv; } /** * Translate key flags into ep11 key attributes and add the attributes to the * attrs in the array. *attrs_len specifies the number of already contained * attributes in the array. */ void ec_key_add_attrs_from_flags(unsigned int flags, CK_ATTRIBUTE attrs[], CK_ULONG *attrs_len, CK_BBOOL *cktrue) { const size_t accepted_flags[] = { XCP_BLOB_MODIFIABLE, XCP_BLOB_RESTRICTABLE, XCP_BLOB_USE_AS_DATA, XCP_BLOB_WRAP, XCP_BLOB_TRUSTED, XCP_BLOB_WRAP_W_TRUSTED, XCP_BLOB_RETAINED }; const CK_ULONG flag2attr[] = { CKA_MODIFIABLE, CKA_IBM_RESTRICTABLE, CKA_IBM_USE_AS_DATA, CKA_WRAP, CKA_TRUSTED, CKA_WRAP_WITH_TRUSTED, CKA_IBM_RETAINKEY }; CK_ATTRIBUTE attr; size_t i, num_attrs = sizeof(flag2attr) / sizeof(CK_ULONG); if (flags == 0) return; attr.pValue = cktrue; attr.ulValueLen = sizeof(CK_BBOOL); for (i = 0; i < num_attrs; i++) { if (flags & accepted_flags[i]) { attr.type = flag2attr[i]; memcpy(&attrs[*attrs_len], &attr, sizeof(CK_ATTRIBUTE)); (*attrs_len)++; } } } /** * The ep11 host lib wants key material in ASN.1 form. We just need some * static ASN.1 encodings for EC public keys. */ void make_asn1_key_sequence(unsigned int curve, const unsigned char *pubkey, unsigned int publen, const unsigned char *privkey, unsigned int privlen, CK_BYTE *seq_buf, CK_ULONG *seq_len) { asn1_p256_key_seq_t p256 = { .seq1 = ZPC_P256_KEY_SEQ1, .ec_pubkey = ZPC_EC_PUBKEY, .ec_params = ZPC_P256_PARAMS, .seq2 = ZPC_P256_KEY_SEQ2, .seq3 = ZPC_P256_KEY_SEQ3, }; asn1_p384_key_seq_t p384 = { .seq1 = ZPC_P384_KEY_SEQ1, .ec_pubkey = ZPC_EC_PUBKEY, .ec_params = ZPC_P384_PARAMS, .seq2 = ZPC_P384_KEY_SEQ2, .seq3 = ZPC_P384_KEY_SEQ3, }; asn1_p521_key_seq_t p521 = { .seq1 = ZPC_P521_KEY_SEQ1, .ec_pubkey = ZPC_EC_PUBKEY, .ec_params = ZPC_P521_PARAMS, .seq2 = ZPC_P521_KEY_SEQ2, .seq3 = ZPC_P521_KEY_SEQ3, }; asn1_ed25519_key_seq_t ed25519 = { .seq1 = ZPC_ED25519_KEY_SEQ1, .ec_pubkey = ZPC_EC_PUBKEY, .ec_params = ZPC_ED25519_PARAMS, .seq2 = ZPC_ED25519_KEY_SEQ2, .seq3 = ZPC_ED25519_KEY_SEQ3, }; asn1_ed448_key_seq_t ed448 = { .seq1 = ZPC_ED448_KEY_SEQ1, .ec_pubkey = ZPC_EC_PUBKEY, .ec_params = ZPC_ED448_PARAMS, .seq2 = ZPC_ED448_KEY_SEQ2, .seq3 = ZPC_ED448_KEY_SEQ3, }; switch (curve) { case 0: memcpy(&p256.privkey, privkey, privlen); memcpy(&p256.pubkey, pubkey, publen); memcpy(seq_buf, &p256, sizeof(p256)); *seq_len = sizeof(p256); break; case 1: memcpy(&p384.privkey, privkey, privlen); memcpy(&p384.pubkey, pubkey, publen); memcpy(seq_buf, &p384, sizeof(p384)); *seq_len = sizeof(p384); break; case 2: memcpy(&p521.privkey, privkey, privlen); memcpy(&p521.pubkey, pubkey, publen); memcpy(seq_buf, &p521, sizeof(p521)); *seq_len = sizeof(p521); break; case 3: memcpy(&ed25519.privkey, privkey, privlen); memcpy(&ed25519.pubkey, pubkey, publen); memcpy(seq_buf, &ed25519, sizeof(ed25519)); *seq_len = sizeof(ed25519); break; case 4: memcpy(&ed448.privkey, privkey, privlen); memcpy(&ed448.pubkey, pubkey, publen); memcpy(seq_buf, &ed448, sizeof(ed448)); *seq_len = sizeof(ed448); break; } } int ec_key_clr2sec_ep11(struct ep11_lib *ep11, unsigned int curve, unsigned int flags, unsigned char *secure_key, unsigned int *seclen, const unsigned char *pubkey, unsigned int publen, const unsigned char *privkey, unsigned int privlen, target_t target) { CK_BYTE iv[PAES_BLOCK_SIZE], cipher[MAX_BLOBSIZE]; CK_BYTE csum[MAX_BLOBSIZE], blob[MAX_BLOBSIZE]; CK_MECHANISM mech_w = { CKM_AES_CBC_PAD, iv, PAES_BLOCK_SIZE }; unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0, cipher_len = sizeof(cipher); CK_ULONG cslen = sizeof(csum), asn1_len; size_t blob_len = MAX_BLOBSIZE; CK_BYTE asn1_buf[1000]; CK_RV rv; int rc, MAX_EP11_ATTRS = 10; /* below 3 defaults plus max 7 from flags */ CK_ATTRIBUTE attrs[MAX_EP11_ATTRS]; CK_ULONG attrs_len = 0; CK_ULONG keyType = CKK_EC; CK_BBOOL cktrue = CK_TRUE; CK_ATTRIBUTE default_attrs[] = { { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, { CKA_IBM_PROTKEY_EXTRACTABLE, &cktrue, sizeof(CK_BBOOL) }, { CKA_SIGN, &cktrue, sizeof(CK_BBOOL) }, }; struct ep11kblob_header *ep11hdr; if (ep11->dll_m_EncryptSingle == NULL || ep11->dll_m_UnwrapKey == NULL) { DEBUG("EP11 host lib function m_EncryptSingle and/or m_UnwrapKey " "not available but required for EP11 EC clear key import."); return -ELIBACC; } /* Create AES wrapping key */ rv = make_wrapblob(ep11, target); if (rv != CKR_OK) { DEBUG("Could not create the wrap blob"); goto ret; } /* Create ASN.1 key struct for m_EncryptSingle */ make_asn1_key_sequence(curve, pubkey, publen, privkey, privlen, (CK_BYTE *)&asn1_buf, &asn1_len); /* Encrypt EC private key with AES wrapping key */ rv = ep11->dll_m_EncryptSingle(ep11->raw2key_wrap_blob, ep11->raw2key_wrap_blob_l, &mech_w, (unsigned char *)asn1_buf, asn1_len, cipher, &cipher_len, target); if (rv != CKR_OK) { DEBUG("Error m_EncryptSingle, rv = 0x%lx", rv); goto ret; } /* Add default attributes */ memcpy(attrs, &default_attrs, sizeof(default_attrs)); attrs_len = sizeof(default_attrs) / sizeof(CK_ATTRIBUTE); /* Add user-defined flags, translated to attributes */ ec_key_add_attrs_from_flags(flags, attrs, &attrs_len, &cktrue); /* Create the secure key blob */ rv = ep11->dll_m_UnwrapKey(cipher, cipher_len, ep11->raw2key_wrap_blob, ep11->raw2key_wrap_blob_l, NULL, ~0, ep11_pin_blob, ep11_pin_blob_len, &mech_w, (CK_ATTRIBUTE *)&attrs, attrs_len, blob, &blob_len, csum, &cslen, target); if (rv != CKR_OK) { DEBUG("Error m_UnwrapKey, rv = 0x%lx", rv); goto ret; } /* Prepend an ep11kblob_header before the secure key blob as required by * keytype PKEY_TYPE_EP11_ECC (= TOKVER_EP11_ECC_WITH_HEADER). */ ep11hdr = (struct ep11kblob_header *)secure_key; ep11hdr->len = blob_len + sizeof(struct ep11kblob_header); ep11hdr->version = PKEY_TYPE_EP11_ECC; ep11hdr->bitlen = curve2bitlen[curve]; /* Copy result */ memcpy(secure_key + sizeof(struct ep11kblob_header), blob, blob_len); *seclen = blob_len + sizeof(struct ep11kblob_header); rv = CKR_OK; ret: switch (rv) { case CKR_OK: rc = 0; break; default: rc = -EIO; break; } return rc; } /** * Extract the public key from given secure ECC key token. To obtain a public * key here, it must be contained in the token. The host lib does not * re-calculate a public key from given secure key. */ int ec_key_extract_public_ep11(struct ep11_lib *ep11, int curve, unsigned char *secure_key, unsigned int seclen, unsigned char *public_key, unsigned int *publen, unsigned char *spki, unsigned int *spkilen, target_t target) { CK_RV rv; CK_BYTE temp[MAX_MACED_SPKI_SIZE] = { 0 }; CK_ULONG temp_len = sizeof(temp); CK_ATTRIBUTE templ[] = { { CKA_IBM_MACED_PUBLIC_KEY_INFO, &temp, temp_len }, }; int rc = -EIO; if (ep11->dll_m_GetAttributeValue == NULL) { DEBUG("EP11 host lib function m_GetAttributeValue not " "available but required for EP11 EC extract public key."); return -ELIBACC; } /* Note that the secure key is a TOKVER_EP11_ECC_WITH_HEADER and has a * 16-byte ep11kblob_header prepended before the actual secure key blob. * This header must not be passed to the ep11 library. */ rv = ep11->dll_m_GetAttributeValue(secure_key + sizeof(struct ep11kblob_header), seclen - sizeof(struct ep11kblob_header), templ, 1, target); if (rv != CKR_OK) { DEBUG("Error m_GetAttributeValue, rv = 0x%lx", rv); goto ret; } if (templ[0].ulValueLen > MAX_MACED_SPKI_SIZE) { DEBUG("EP11 host lib function dll_m_GetAttributeValue returned an" "SPKI with %ld bytes. Cannot be handled.", templ[0].ulValueLen); goto ret; } memcpy(spki, temp, templ[0].ulValueLen); *spkilen = templ[0].ulValueLen; memcpy(public_key, temp + curve2puboffset[curve], curve2publen[curve]); *publen = curve2publen[curve]; rc = 0; ret: return rc; } int ec_key_generate_ep11(struct ep11_lib *ep11, int curve, unsigned int flags, unsigned char *secure_key, unsigned int *seclen, unsigned char *public_key, unsigned int *publen, unsigned char *spki, unsigned int *spkilen, target_t target) { unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; CK_MECHANISM mech = { CKM_EC_KEY_PAIR_GEN, NULL, 0 }; CK_BYTE blob[MAX_BLOBSIZE]; size_t blob_len = MAX_BLOBSIZE; unsigned char maced_spki[MAX_BLOBSIZE]; unsigned long maced_spki_len = sizeof(maced_spki); int rc; CK_RV rv; CK_BYTE *q; size_t qlen; int MAX_EP11_ATTRS = 15; CK_ATTRIBUTE priv_attrs[MAX_EP11_ATTRS]; CK_BBOOL cktrue = CK_TRUE; CK_ATTRIBUTE default_priv_attrs[] = { {CKA_IBM_PROTKEY_EXTRACTABLE, &cktrue, sizeof(cktrue)}, {CKA_PRIVATE, &cktrue, sizeof(cktrue)}, {CKA_SIGN, &cktrue, sizeof(cktrue)}, }; CK_ATTRIBUTE pub_attrs[] = { { CKA_VERIFY, &cktrue, sizeof(cktrue) }, { CKA_EC_PARAMS, (unsigned char *)curve2spki_ec_params[curve], curve2spki_ec_params_len[curve] }, }; CK_ULONG pub_attrs_len = sizeof(pub_attrs) / sizeof(CK_ATTRIBUTE); CK_ULONG priv_attrs_len; struct ep11kblob_header *ep11hdr; if (ep11->dll_m_GenerateKeyPair == NULL) { DEBUG("EP11 host lib function m_GenerateKeyPair not " "available but required for EP11 EC key generate."); return -EIO; } /* Add default attributes */ memcpy(&priv_attrs, &default_priv_attrs, sizeof(default_priv_attrs)); priv_attrs_len = sizeof(default_priv_attrs) / sizeof(CK_ATTRIBUTE); /* Add user-defined flags, translated to attributes */ ec_key_add_attrs_from_flags(flags, priv_attrs, &priv_attrs_len, &cktrue); /* Generate the secure key blob */ rv = ep11->dll_m_GenerateKeyPair(&mech, pub_attrs, pub_attrs_len, priv_attrs, priv_attrs_len, ep11_pin_blob, ep11_pin_blob_len, blob, &blob_len, maced_spki, &maced_spki_len, target); if (rv != CKR_OK) { DEBUG("Error m_GenerateKeyPair, rv = 0x%lx", rv); rc = EIO; goto ret; } /* Get public key from spki */ if (maced_spki_len > MAX_BLOBSIZE || blob_len > MAX_BLOBSIZE) { DEBUG("Invalid spki size from m_GenerateKeyPair: %ld bytes", maced_spki_len); rc = EIO; goto ret; } q = maced_spki + curve2puboffset[curve]; qlen = curve2publen[curve]; /* Copy public key and spki */ memcpy(public_key, q, qlen); *publen = qlen; memcpy(spki, maced_spki, maced_spki_len); *spkilen = maced_spki_len; /* Copy secure key, which is of type TOKVER_EP11_ECC_WITH_HEADER. It has * a 16-byte header prepended before the actual secure key blob. Refer * to kernel zcrypt_ep11misc.h. Fill out this header in the key struct. * This info is later needed for sec2prot. */ memset(secure_key, 0, sizeof(struct ep11kblob_header)); memcpy(secure_key + sizeof(struct ep11kblob_header), blob, blob_len); *seclen = blob_len + sizeof(struct ep11kblob_header); ep11hdr = (struct ep11kblob_header *)secure_key; ep11hdr->len = blob_len + sizeof(struct ep11kblob_header); ep11hdr->version = PKEY_TYPE_EP11_ECC; ep11hdr->bitlen = curve2bitlen[curve]; rc = 0; ret: return rc; } int ep11_get_raw_blob_length(const unsigned char *blob) { struct ep11kblob_header *hdr = (struct ep11kblob_header *)blob; return hdr->len; } void ep11_make_spki(int curve, const unsigned char *pubkey, unsigned int publen, unsigned char *spki, unsigned int *spki_len) { p256_maced_spki_t p256 = { .seq1 = ZPC_P256_SPKI_SEQ1, .ec_pubkey = ZPC_EC_PUBKEY, .ec_params = ZPC_P256_PARAMS, .seq2 = ZPC_P256_SPKI_SEQ2, }; p384_maced_spki_t p384 = { .seq1 = ZPC_P384_SPKI_SEQ1, .ec_pubkey = ZPC_EC_PUBKEY, .ec_params = ZPC_P384_PARAMS, .seq2 = ZPC_P384_SPKI_SEQ2, }; p521_maced_spki_t p521 = { .seq1 = ZPC_P521_SPKI_SEQ1, .ec_pubkey = ZPC_EC_PUBKEY, .ec_params = ZPC_P521_PARAMS, .seq2 = ZPC_P521_SPKI_SEQ2, }; ed25519_maced_spki_t ed25519 = { .seq1 = ZPC_ED25519_SPKI_SEQ1, .ec_pubkey = ZPC_EC_PUBKEY, .ec_params = ZPC_ED25519_PARAMS, .seq2 = ZPC_ED25519_SPKI_SEQ2, }; ed448_maced_spki_t ed448 = { .seq1 = ZPC_ED448_SPKI_SEQ1, .ec_pubkey = ZPC_EC_PUBKEY, .ec_params = ZPC_ED448_PARAMS, .seq2 = ZPC_ED448_SPKI_SEQ2, }; switch (curve) { case 0: memcpy(&p256.pubkey, pubkey, publen); memcpy(spki, &p256, sizeof(p256)); *spki_len = sizeof(p256) - EP11_SPKI_MACLEN; break; case 1: memcpy(&p384.pubkey, pubkey, publen); memcpy(spki, &p384, sizeof(p384)); *spki_len = sizeof(p384) - EP11_SPKI_MACLEN; break; case 2: memcpy(&p521.pubkey, pubkey, publen); memcpy(spki, &p521, sizeof(p521)); *spki_len = sizeof(p521) - EP11_SPKI_MACLEN; break; case 3: memcpy(&ed25519.pubkey, pubkey, publen); memcpy(spki, &ed25519, sizeof(ed25519)); *spki_len = sizeof(ed25519) - EP11_SPKI_MACLEN; break; case 4: memcpy(&ed448.pubkey, pubkey, publen); memcpy(spki, &ed448, sizeof(ed448)); *spki_len = sizeof(ed448) - EP11_SPKI_MACLEN; break; } } int ep11_make_maced_spki(struct ep11_lib *ep11, const CK_BYTE *spki, unsigned int spki_len, CK_BYTE *maced_spki, unsigned int *maced_spkilen, target_t target) { CK_BYTE csum[MAX_BLOBSIZE]; CK_MECHANISM mech = { CKM_IBM_TRANSPORTKEY, 0, 0 }; unsigned char *ep11_pin_blob = NULL; CK_ULONG ep11_pin_blob_len = 0; CK_ULONG cslen = sizeof(csum); CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_ATTRIBUTE attrs[] = { { CKA_CLASS, &class, sizeof(class) }, }; CK_ATTRIBUTE *p_attrs = (CK_ATTRIBUTE *)&attrs; CK_ULONG attrs_len = sizeof(attrs) / sizeof(CK_ATTRIBUTE); CK_ULONG ul_maced_spkilen = *maced_spkilen; CK_RV rv; int rc; if (spki == NULL || spki_len == 0) return 0; if (ep11->dll_m_UnwrapKey == NULL) { DEBUG("EP11 host lib function m_UnwrapKey not available but " "required for creating an EP11 MACed public key SPKI."); return -ELIBACC; } rv = ep11->dll_m_UnwrapKey(spki, spki_len, NULL, 0, NULL, 0, ep11_pin_blob, ep11_pin_blob_len, &mech, p_attrs, attrs_len, maced_spki, &ul_maced_spkilen, csum, &cslen, target); if (rv != CKR_OK) { DEBUG("Error m_UnwrapKey, rv = 0x%lx", rv); goto ret; } *maced_spkilen = ul_maced_spkilen; rv = CKR_OK; ret: switch (rv) { case CKR_OK: rc = 0; break; default: rc = -EIO; break; } return rc; } /** * Check if the spki buffer contains an expected SPKI, which means it should * at least match with the curve of the key object. */ int ep11_spki_valid_for_curve(int curve, const unsigned char *spki, unsigned int len) { /* This can be either a raw or a maced spki. */ if (len < (curve2macedspkilen[curve] - EP11_SPKI_MACLEN) || len > curve2macedspkilen[curve]) return 0; /* Looks like length is ok, now check if static parts are as expected */ if (memcmp(spki, curve2spki_seq1[curve], curve2spki_seq1_len[curve]) != 0 || memcmp(spki + curve2spki_seq1_len[curve], ec_pubkey, ec_pubkey_len) != 0 || memcmp(spki + curve2spki_seq1_len[curve] + ec_pubkey_len, curve2spki_ec_params[curve], curve2spki_ec_params_len[curve]) != 0) return 0; return 1; } int ep11_check_wk(struct ep11_lib *ep11, const unsigned char *wk_id, unsigned int wk_id_len, target_t target, bool verbose) { CK_IBM_DOMAIN_INFO dinf; CK_ULONG dinf_len = sizeof(dinf); CK_RV rv; if (ep11->dll_m_get_xcp_info == NULL) { pr_verbose(verbose, "EP11 host lib function m_get_xcp_info not " "available but required for EP11 EC key reencipher."); return -ELIBACC; } rv = ep11->dll_m_get_xcp_info(&dinf, &dinf_len, CK_IBM_XCPQ_DOMAIN, 0, target); if (rv != CKR_OK) { pr_verbose(verbose, "Failed to query domain information " "m_get_xcp_info rc: 0x%lx", rv); return -EIO; } if (memcmp(wk_id, dinf.wk, wk_id_len) != 0) return -EIO; return 0; } libzpc-1.3.0/src/zkey/ep11.h000066400000000000000000000425711475140344100155020ustar00rootroot00000000000000/* * zkey - Generate, re-encipher, and validate secure keys * * This header file defines the interface to the EP11 host library. * * Copyright IBM Corp. 2019 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef EP11_H #define EP11_H #include #include #include "lib/zt_common.h" /* EP11 definitions */ #define CKK_EC 0x00000003 #define CKO_PUBLIC_KEY 0x00000002 #define MAX_CSUMSIZE 64 static const char wrap_key_name[] = "EP11_wrapkey"; #define CK_TRUE 1 #define CK_FALSE 0 typedef uint64_t target_t; typedef unsigned long int CK_ULONG; typedef CK_ULONG CK_RV; typedef unsigned char CK_BYTE; typedef CK_BYTE CK_CHAR; typedef CK_ULONG *CK_ULONG_PTR; typedef void *CK_VOID_PTR; typedef CK_BYTE CK_BBOOL; typedef CK_ULONG CK_OBJECT_CLASS; typedef CK_ULONG CK_ATTRIBUTE_TYPE; typedef struct CK_ATTRIBUTE { CK_ATTRIBUTE_TYPE type; CK_VOID_PTR pValue; CK_ULONG ulValueLen; /* in bytes */ } CK_ATTRIBUTE; #define CKA_CLASS 0x00000000 #define CKA_TOKEN 0x00000001 #define CKA_PRIVATE 0x00000002 #define CKA_LABEL 0x00000003 #define CKA_TRUSTED 0x00000086 #define CKA_KEY_TYPE 0x00000100 #define CKA_ENCRYPT 0x00000104 #define CKA_DECRYPT 0x00000105 #define CKA_WRAP 0x00000106 #define CKA_UNWRAP 0x00000107 #define CKA_SIGN 0x00000108 #define CKA_VERIFY 0x0000010A #define CKA_VALUE_LEN 0x00000161 #define CKA_EXTRACTABLE 0x00000162 #define CKA_MODIFIABLE 0x00000170 #define CKA_EC_PARAMS 0x00000180 #define CKA_EC_POINT 0x00000181 #define CKA_WRAP_WITH_TRUSTED 0x00000210 #define CKA_VENDOR_DEFINED 0x80000000 #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_USE_AS_DATA (CKA_VENDOR_DEFINED +0x10008) #define CKA_IBM_PROTKEY_EXTRACTABLE (CKA_VENDOR_DEFINED +0x1000c) /* Available with ep11 hostlib v4: */ #define CKA_IBM_MACED_PUBLIC_KEY_INFO (CKA_VENDOR_DEFINED +0x20002) typedef CK_ULONG CK_MECHANISM_TYPE; typedef struct CK_MECHANISM { CK_MECHANISM_TYPE mechanism; CK_VOID_PTR pParameter; CK_ULONG ulParameterLen; /* in bytes */ } CK_MECHANISM; #define CKM_EC_KEY_PAIR_GEN 0x00001040 #define CKM_AES_CBC_PAD 0x00001085 #define CKM_AES_KEY_GEN 0x00001080 #define CKM_VENDOR_DEFINED 0x80000000 #define CKM_IBM_TRANSPORTKEY (CKM_VENDOR_DEFINED +0x20005) typedef struct XCP_ModuleSocket { char host[256 + 1]; uint32_t port; } *XCP_ModuleSocket_t; typedef struct XCP_DomainPerf { unsigned int lastperf[256]; } *XCP_DomainPerf_t; typedef struct XCP_Module { uint32_t version; uint64_t flags; uint32_t domains; unsigned char domainmask[256 / 8]; struct XCP_ModuleSocket socket; uint32_t module_nr; void *mhandle; struct XCP_DomainPerf perf; /* ----- end of v1 fields ----- */ uint32_t api; /* ----- end of v2 fields ----- */ } *XCP_Module_t; typedef enum { XCP_MFL_SOCKET = 1, XCP_MFL_MODULE = 2, XCP_MFL_MHANDLE = 4, XCP_MFL_PERF = 8, XCP_MFL_VIRTUAL = 0x10, XCP_MFL_STRICT = 0x20, XCP_MFL_PROBE = 0x40, XCP_MFL_ALW_TGT_ADD = 0x80, XCP_MFL_MAX = 0xff } XCP_Module_Flags; #define XCP_MOD_VERSION_1 1 #define XCP_MOD_VERSION_2 2 #define XCP_TGT_INIT ~0UL #define XCPTGTMASK_SET_DOM(mask, domain) \ mask[((domain)/8)] |= (1 << (7-(domain)%8)) typedef enum { XCP_BLOB_EXTRACTABLE = 1, XCP_BLOB_NEVER_EXTRACTABLE = 2, XCP_BLOB_MODIFIABLE = 4, XCP_BLOB_NEVER_MODIFIABLE = 8, XCP_BLOB_RESTRICTABLE = 0x10, XCP_BLOB_LOCAL = 0x20, XCP_BLOB_ATTRBOUND = 0x40, XCP_BLOB_USE_AS_DATA = 0x80, XCP_BLOB_SIGN = 0x0100, XCP_BLOB_SIGN_RECOVER = 0x0200, XCP_BLOB_DECRYPT = 0x0400, XCP_BLOB_ENCRYPT = 0x0800, XCP_BLOB_DERIVE = 0x1000, XCP_BLOB_UNWRAP = 0x2000, XCP_BLOB_WRAP = 0x4000, XCP_BLOB_VERIFY = 0x8000, XCP_BLOB_VERIFY_RECOVER = 0x010000, XCP_BLOB_TRUSTED = 0x020000, XCP_BLOB_WRAP_W_TRUSTED = 0x040000, XCP_BLOB_RETAINED = 0x080000, XCP_BLOB_ALWAYS_RETAINED = 0x100000, XCP_BLOB_PROTKEY_EXTRACTABLE = 0x200000, XCP_BLOB_PROTKEY_NEVER_EXTRACTABLE = 0x400000, } XCP_Key_Flags; #define XCP_SERIALNR_CHARS 8 #define XCP_ADMCTR_BYTES ((size_t) (128/8)) #define XCP_KEYCSUM_BYTES (256/8) #define XCP_ADM_REENCRYPT 25 /* transform blobs to next WK */ #define MAX_BLOBSIZE 8192 #define CKR_VENDOR_DEFINED 0x80000000 #define CKR_IBM_WKID_MISMATCH CKR_VENDOR_DEFINED + 0x10001 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; const unsigned char *payload; size_t pllen; } *XCPadmresp_t; 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_DOM_COMMITTED_NWK 8 #define CK_IBM_XCPHQ_VERSION 0xff000001 #define CK_IBM_XCPQ_DOMAIN 3 #define MAX_APQN 256 typedef struct { short format; short length; short apqns[2 * MAX_APQN]; } __packed ep11_target_t; #define CKR_OK 0x00000000 #define CKR_FUNCTION_NOT_SUPPORTED 0x00000054 typedef int (*m_init_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 unsigned long int (*m_admin_t)(unsigned char *resp1, size_t *r1len, unsigned char *resp2, size_t *r2len, const unsigned char *cmd, size_t clen, const unsigned char *sigs, size_t slen, target_t target); typedef long (*xcpa_cmdblock_t)(unsigned char *blk, size_t blen, unsigned int fn, const struct XCPadmresp *minf, const unsigned char *tctr, const unsigned char *payload, size_t plen); typedef long (*xcpa_internal_rv_t)(const unsigned char *rsp, size_t rlen, struct XCPadmresp *rspblk, CK_RV *rv); typedef unsigned long int (*m_UnwrapKey_t)(const unsigned char *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 *uwmech, const CK_ATTRIBUTE *ptempl, CK_ULONG pcount, unsigned char *unwrapped, size_t * uwlen, unsigned char *csum, CK_ULONG * cslen, target_t target); typedef unsigned long int (*m_EncryptSingle_t)(const unsigned char *key, size_t klen, CK_MECHANISM *mech, unsigned char *plain, CK_ULONG plen, unsigned char *cipher, CK_ULONG_PTR clen, target_t target); typedef unsigned long int (*m_GenerateKeyPair_t)(CK_MECHANISM *pmech, CK_ATTRIBUTE *ppublic, unsigned long pubattrs, CK_ATTRIBUTE *pprivate, unsigned long prvattrs, const unsigned char *pin, size_t pinlen, unsigned char *key, size_t * klen, unsigned char *pubkey, size_t * pklen, target_t target); typedef unsigned long int (*m_GenerateKey_t)(CK_MECHANISM *pmech, CK_ATTRIBUTE *templ, 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 unsigned long int (*m_GetAttributeValue_t) (const unsigned char *blob, size_t bloblen, CK_ATTRIBUTE *templ, CK_ULONG templcount, target_t target); struct ep11_version { unsigned int major; unsigned int minor; unsigned int modification; }; struct ep11_lib { void *lib_ep11; m_init_t dll_m_init; 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; m_admin_t dll_m_admin; xcpa_cmdblock_t dll_xcpa_cmdblock; xcpa_internal_rv_t dll_xcpa_internal_rv; m_UnwrapKey_t dll_m_UnwrapKey; m_EncryptSingle_t dll_m_EncryptSingle; m_GenerateKeyPair_t dll_m_GenerateKeyPair; m_GenerateKey_t dll_m_GenerateKey; m_GetAttributeValue_t dll_m_GetAttributeValue; struct ep11_version version; CK_BYTE raw2key_wrap_blob[MAX_BLOBSIZE]; size_t raw2key_wrap_blob_l; }; /* * ASN.1 constants for static key sequences below. */ #define ZPC_P256_PARAMS {0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07} #define ZPC_P384_PARAMS {0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22} #define ZPC_P521_PARAMS {0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23} #define ZPC_ED25519_PARAMS {0x06, 0x03, 0x2B, 0x65, 0x70} #define ZPC_ED448_PARAMS {0x06, 0x03, 0x2B, 0x65, 0x71} #define ZPC_EC_PUBKEY {0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01} #define ZPC_P256_KEY_SEQ1 {0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13} #define ZPC_P384_KEY_SEQ1 {0x30, 0x81, 0xB6, 0x02, 0x01, 0x00, 0x30, 0x10} #define ZPC_P521_KEY_SEQ1 {0x30, 0x81, 0xEE, 0x02, 0x01, 0x00, 0x30, 0x10} #define ZPC_ED25519_KEY_SEQ1 {0x30, 0x61, 0x02, 0x01, 0x00, 0x30, 0x0E} #define ZPC_ED448_KEY_SEQ1 {0x30, 0x81, 0x93, 0x02, 0x01, 0x00, 0x30, 0x0E} #define ZPC_P256_KEY_SEQ2 {0x04, 0x6D, 0x30, 0x6B, 0x02, 0x01, 0x01, 0x04, 0x20} #define ZPC_P384_KEY_SEQ2 {0x04, 0x81, 0x9E, 0x30, 0x81, 0x9B, 0x02, 0x01, 0x01, 0x04, 0x30} #define ZPC_P521_KEY_SEQ2 {0x04, 0x81, 0xD6, 0x30, 0x81, 0xD3, 0x02, 0x01, 0x01, 0x04, 0x42} #define ZPC_ED25519_KEY_SEQ2 {0x04, 0x4C, 0x30, 0x4A, 0x02, 0x01, 0x01, 0x04, 0x20} #define ZPC_ED448_KEY_SEQ2 {0x04, 0x7E, 0x30, 0x7C, 0x02, 0x01, 0x01, 0x04, 0x39} #define ZPC_P256_KEY_SEQ3 {0xA1, 0x44, 0x03, 0x42, 0x00, 0x04} #define ZPC_P384_KEY_SEQ3 {0xA1, 0x64, 0x03, 0x62, 0x00, 0x04} #define ZPC_P521_KEY_SEQ3 {0xA1, 0x81, 0x89, 0x03, 0x81, 0x86, 0x00, 0x04} #define ZPC_ED25519_KEY_SEQ3 {0xA1, 0x23, 0x03, 0x21, 0x00} #define ZPC_ED448_KEY_SEQ3 {0xA1, 0x3C, 0x03, 0x3A, 0x00} /** * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type) * OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve) * BIT STRING (520 bit) ... */ typedef struct { CK_BYTE seq1[8]; CK_BYTE ec_pubkey[9]; CK_BYTE ec_params[10]; CK_BYTE seq2[9]; CK_BYTE privkey[32]; CK_BYTE seq3[6]; CK_BYTE pubkey[64]; } __attribute__((packed)) asn1_p256_key_seq_t; /** * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type) * OBJECT IDENTIFIER 1.3.132.0.34 secp384r1 (SECG (Certicom) named elliptic curve) * BIT STRING (776 bit) ... */ typedef struct { CK_BYTE seq1[8]; CK_BYTE ec_pubkey[9]; CK_BYTE ec_params[7]; CK_BYTE seq2[11]; CK_BYTE privkey[48]; CK_BYTE seq3[6]; CK_BYTE pubkey[96]; } __attribute__((packed)) asn1_p384_key_seq_t; /** * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type) * OBJECT IDENTIFIER 1.3.132.0.35 secp521r1 (SECG (Certicom) named elliptic curve) * BIT STRING (1064 bit) ... */ typedef struct { CK_BYTE seq1[8]; CK_BYTE ec_pubkey[9]; CK_BYTE ec_params[7]; CK_BYTE seq2[11]; CK_BYTE privkey[66]; CK_BYTE seq3[8]; CK_BYTE pubkey[132]; } __attribute__((packed)) asn1_p521_key_seq_t; /** * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type) * OBJECT IDENTIFIER 1.3.101.112 curveEd25519 (EdDSA 25519 signature algorithm) * BIT STRING (256 bit) ... */ typedef struct { CK_BYTE seq1[7]; CK_BYTE ec_pubkey[9]; CK_BYTE ec_params[5]; CK_BYTE seq2[9]; CK_BYTE privkey[32]; CK_BYTE seq3[5]; CK_BYTE pubkey[32]; } __attribute__((packed)) asn1_ed25519_key_seq_t; /** * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type) * OBJECT IDENTIFIER 1.3.101.113 curveEd448 (EdDSA 448 signature algorithm) * BIT STRING (456 bit) ... */ typedef struct { CK_BYTE seq1[8]; CK_BYTE ec_pubkey[9]; CK_BYTE ec_params[5]; CK_BYTE seq2[9]; CK_BYTE privkey[57]; CK_BYTE seq3[5]; CK_BYTE pubkey[57]; } __attribute__((packed)) asn1_ed448_key_seq_t; #define EP11_SPKI_MACLEN 256 #define ZPC_P256_SPKI_SEQ1 {0x30, 0x59, 0x30, 0x13} #define ZPC_P384_SPKI_SEQ1 {0x30, 0x76, 0x30, 0x10} #define ZPC_P521_SPKI_SEQ1 {0x30, 0x81, 0x9B, 0x30, 0x10} #define ZPC_ED25519_SPKI_SEQ1 {0x30, 0x33, 0x30, 0x0E} #define ZPC_ED448_SPKI_SEQ1 {0x30, 0x4C, 0x30, 0x0E} #define ZPC_P256_SPKI_SEQ2 {0x03, 0x42, 0x00, 0x04} #define ZPC_P384_SPKI_SEQ2 {0x03, 0x62, 0x00, 0x04} #define ZPC_P521_SPKI_SEQ2 {0x03, 0x81, 0x86, 0x00, 0x04} #define ZPC_ED25519_SPKI_SEQ2 {0x03, 0x21, 0x00} #define ZPC_ED448_SPKI_SEQ2 {0x03, 0x3A, 0x00} /** * ep11 wire spec: SPKI with MAC */ typedef struct { CK_BYTE wk_id_octet_string[2]; CK_BYTE wk_id[16]; CK_BYTE session_id_octet_string[2]; CK_BYTE session_id[32]; CK_BYTE salt_octet_string[2]; CK_BYTE salt[8]; CK_BYTE mode_octet_string[2]; CK_BYTE mode_id[8]; CK_BYTE variable_part[0]; /* variable length attributes and MAC */ } __attribute__((packed)) spki_mac_t; /** * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type) * OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve) * BIT STRING ... */ typedef struct { CK_BYTE seq1[4]; CK_BYTE ec_pubkey[9]; CK_BYTE ec_params[10]; CK_BYTE seq2[4]; CK_BYTE pubkey[64]; CK_BYTE mac[EP11_SPKI_MACLEN]; } __attribute__((packed)) p256_maced_spki_t; typedef struct { CK_BYTE seq1[4]; CK_BYTE ec_pubkey[9]; CK_BYTE ec_params[7]; CK_BYTE seq2[4]; CK_BYTE pubkey[96]; CK_BYTE mac[EP11_SPKI_MACLEN]; } __attribute__((packed)) p384_maced_spki_t; typedef struct { CK_BYTE seq1[5]; CK_BYTE ec_pubkey[9]; CK_BYTE ec_params[7]; CK_BYTE seq2[5]; CK_BYTE pubkey[132]; CK_BYTE mac[EP11_SPKI_MACLEN]; } __attribute__((packed)) p521_maced_spki_t; typedef struct { CK_BYTE seq1[4]; CK_BYTE ec_pubkey[9]; CK_BYTE ec_params[5]; CK_BYTE seq2[3]; CK_BYTE pubkey[32]; CK_BYTE mac[EP11_SPKI_MACLEN]; } __attribute__((packed)) ed25519_maced_spki_t; typedef struct { CK_BYTE seq1[4]; CK_BYTE ec_pubkey[9]; CK_BYTE ec_params[5]; CK_BYTE seq2[3]; CK_BYTE pubkey[57]; CK_BYTE mac[EP11_SPKI_MACLEN]; } __attribute__((packed)) ed448_maced_spki_t; int load_ep11_library(struct ep11_lib *ep11, bool verbose); int get_ep11_target_for_apqn(struct ep11_lib *ep11, unsigned int card, unsigned int domain, target_t *target, bool verbose); void free_ep11_target_for_apqn(struct ep11_lib *ep11, target_t target); int reencipher_ep11_key(struct ep11_lib *ep11, target_t target, unsigned int card, unsigned int domain, u8 *secure_key, unsigned int secure_key_size, bool verbose); int ec_key_clr2sec_ep11(struct ep11_lib *ep11, unsigned int curve, unsigned int flags, unsigned char *sec, unsigned int *seclen, const unsigned char *pubkey, unsigned int publen, const unsigned char *privkey, unsigned int privlen, target_t target); int ec_key_extract_public_ep11(struct ep11_lib *ep11, int curve, unsigned char *ecc_token, unsigned int ecc_token_len, unsigned char *ecc_pub_token, unsigned int *p_ecc_pub_token_len, unsigned char *spki, unsigned int *spkilen, target_t target); int ec_key_generate_ep11(struct ep11_lib *ep11, int curve, unsigned int flags, unsigned char *secure_key, unsigned int *seclen, unsigned char *public_key, unsigned int *publen, unsigned char *spki, unsigned int *spkilen, target_t target); int ep11_blob_has_spki(const unsigned char *blob, unsigned int blob_len); int ep11_get_raw_blob_length(const unsigned char *blob); int ep11_get_spki_from_buf(const unsigned char *buf, unsigned int buf_len, int curve, unsigned char *spki, unsigned int *raw_spki_len, target_t target); void ep11_make_spki(int curve, const unsigned char *pubkey, unsigned int publen, unsigned char *spki, unsigned int *spki_len); int ep11_make_maced_spki(struct ep11_lib *ep11, const CK_BYTE *spki, unsigned int spki_len, CK_BYTE *maced_spki, unsigned int *maced_spkilen, target_t target); int ep11_spki_valid_for_curve(int curve, const unsigned char *spki, unsigned int len); int ep11_check_wk(struct ep11_lib *ep11, const unsigned char *wk_id, unsigned int wk_id_len, target_t target, bool verbose); #endif libzpc-1.3.0/src/zkey/lib/000077500000000000000000000000001475140344100153205ustar00rootroot00000000000000libzpc-1.3.0/src/zkey/lib/util_base.c000066400000000000000000000111611475140344100174330ustar00rootroot00000000000000/* * util - Utility function library * * General helper functions * * Copyright IBM Corp. 2013, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include #include "lib/util_base.h" #include "lib/util_libc.h" /* * Print hexdump for buffer with variable group parameter */ void util_hexdump_grp(FILE *fh, const char *tag, const void *data, int grp, int count, int indent) { const char *buf = data; int i, first = 1; for (i = 0; i < count; i++) { if (first) { fprintf(fh, "%*s", indent, " "); if (tag) fprintf(fh, "%s: ", tag); fprintf(fh, "%08x: ", i); first = 0; } fprintf(fh, "%02x", buf[i]); if (i % 16 == 15 || i + 1 == count) { fprintf(fh, "\n"); first = 1; } else if (i % grp == grp - 1) { fprintf(fh, " "); } } } /* * Print hexdump for buffer with fix grp parameter */ void util_hexdump(FILE *fh, const char *tag, const void *data, int count) { util_hexdump_grp(fh, tag, data, sizeof(long), count, 0); } #define MAX_CHARS_PER_LINE 80 /* * Print string with indentation * * Print a string while accounting for a given indent value, characters per line * limit, and line breaks ('\n') within the string. The first line has to be * indented manually. * * @param[in] str String that should be printed * @param[in] indent Indentation for printing */ void util_print_indented(const char *str, int indent) { char *word, *line, *desc, *desc_ptr; int word_len, pos = indent; desc = desc_ptr = util_strdup(str); line = strsep(&desc, "\n"); while (line) { word = strsep(&line, " "); pos = indent; while (word) { word_len = strlen(word); if (pos + word_len + 1 > MAX_CHARS_PER_LINE) { 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); } /** * Determines the absolute name of an s390-tools system directory * (it could be data, or library directory) */ static const char *util_sysdir(const char *env_var, const char *default_dir) { return secure_getenv(env_var) ?: default_dir; } /** * Determines the absolute name of a file installed in the s390-tools * system directory */ static const char *util_sysdir_path(const char *filename, const char *dirname) { static char libdir_pathname[PATH_MAX]; int ret; ret = snprintf(libdir_pathname, sizeof(libdir_pathname), "%s/%s", dirname, filename); if (ret < 0 || ret >= (int)sizeof(libdir_pathname)) errx(EXIT_FAILURE, "Could not compose absolute pathname of %s and %s", dirname, filename); return libdir_pathname; } /** * Determines the absolute name of a s390-tools library directory * * Resources are handled by the library * * @returns Pointer to a buffer, which contains the null-terminated name */ const char *util_libdir(void) { return util_sysdir("S390TOOLS_LIBDIR", TOOLS_LIBDIR); } /** * Determines the absolute name of a file installed in the s390-tools * library directory by its relative name. * * Resources are handled by the library. A second call of this function * overwrites previously returned data. Care must be taken when attempting * to do a second call. * * @param[in] filename Null-terminated file name relative to the s390-tools * library directory * @returns Pointer to a buffer of PATH_MAX size, which contains the * null-terminated absolute name */ const char *util_libdir_path(const char *filename) { return util_sysdir_path(filename, util_libdir()); } /** * Determines the absolute name of a s390-tools data directory * * Resources are handled by the library * * @returns Pointer to a buffer which contains the null-terminated name */ const char *util_datadir(void) { return util_sysdir("S390TOOLS_DATADIR", TOOLS_DATADIR); } /** * Determines the absolute name of a file installed in the s390-tools * data directory by its relative name. * * Resources are handled by the library. A second call of this function * overwrites previously returned data. Care must be taken when attempting * to do a second call. * * @param[in] filename Null-terminated file name relative to the s390-tools * data directory * @returns Pointer to a buffer of PATH_MAX size, which contains the * null-terminated absolute name */ const char *util_datadir_path(const char *filename) { return util_sysdir_path(filename, util_datadir()); } libzpc-1.3.0/src/zkey/lib/util_base.h000066400000000000000000000017231475140344100174430ustar00rootroot00000000000000/* * util - Utility function library * * General helper functions * * Copyright IBM Corp. 2013, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef LIB_UTIL_BASE_H #define LIB_UTIL_BASE_H #include #include #include "zt_common.h" void util_hexdump(FILE *fh, const char *tag, const void *data, int cnt); void util_hexdump_grp(FILE *fh, const char *tag, const void *data, int group, int cnt, int indent); void util_print_indented(const char *str, int indent); const char *util_libdir(void); const char *util_libdir_path(const char *filename); const char *util_datadir(void); const char *util_datadir_path(const char *filename); static inline void util_ptr_vec_free(void **ptr_vec, int count) { int i; if (!ptr_vec || count < 0) return; for (i = 0; i < count; i++) free(ptr_vec[i]); free(ptr_vec); } #endif /* LIB_UTIL_BASE_H */ libzpc-1.3.0/src/zkey/lib/util_file.c000066400000000000000000000303301475140344100174370ustar00rootroot00000000000000/* * util - Utility function library * * Read and write files * * Copyright IBM Corp. 2016, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include #include #include #include #include #include #include #include #include "lib/util_base.h" #include "lib/util_file.h" #include "lib/util_libc.h" #include "lib/util_panic.h" #include "lib/util_prg.h" /* * Read the first line of a file into given buffer */ static int file_gets(char *str, size_t size, const char *path) { char *p, *end; FILE *fp; int rc; /* In case of error we always return empty string */ str[0] = 0; /* Read the string */ fp = fopen(path, "r"); if (!fp) return -1; p = fgets(str, size, fp); if (p) { /* Check for end of line */ end = memchr(str, '\n', size); if (end) *end = 0; else str[size - 1] = 0; } if (strlen(str) == 0) { rc = -1; goto out_fclose; } rc = 0; out_fclose: fclose(fp); return rc; } /** * Read the first line of a file * * If read is successful 'str' contains first line of a file without the * trailing newline. If read fails, an empty string is returned for 'str' * The resulting string will always be null-terminated. * * @param[out] str Result buffer * @param[in] size Size of the result buffer * @param[in] fmt Format string for generation of the path name * @param[in] ... Parameters for format string * * @retval 0 File was read * @retval -1 Error while reading file */ int util_file_read_line(char *const str, size_t size, const char *fmt, ...) { char path[PATH_MAX]; va_list ap; /* Construct the file name */ UTIL_VSPRINTF(path, fmt, ap); return file_gets(str, size, path); } /* * Write string to a file */ static int file_puts(const char *str, const char *path) { FILE *fp; int rc; /* write the string */ fp = fopen(path, "w"); if (!fp) return -1; if (fputs(str, fp) == EOF) { rc = -1; goto out_fclose; } rc = 0; out_fclose: fclose(fp); return rc; } /** * Write string to a file without the terminating null byte * * @param[in] str Content is to be written * @param[in] fmt Format string for generation of the path name * @param[in] ... Parameters for format string * * @retval 0 Write was successful * @retval -1 Error while writing file */ int util_file_write_s(const char *str, const char *fmt, ...) { char path[PATH_MAX]; va_list ap; /* Construct the file name */ UTIL_VSPRINTF(path, fmt, ap); return file_puts(str, path); } /** * Write signed long value to a file according to given base * * @param[in] val Value is to be written * @param[in] base Base for conversion, either 8, 10, or 16 * @param[in] fmt Format string for generation of the path name * @param[in] ... Parameters for format string * * @retval 0 Write was successful * @retval -1 Error while writing file */ int util_file_write_l(long val, int base, const char *fmt, ...) { char *str, path[PATH_MAX]; va_list ap; int rc; /* Construct the file name */ UTIL_VSPRINTF(path, fmt, ap); switch (base) { case 8: util_asprintf(&str, "%lo", val); break; case 10: util_asprintf(&str, "%ld", val); break; case 16: util_asprintf(&str, "%lx", val); break; default: util_panic("Invalid base: %d\n", base); } rc = file_puts(str, path); free(str); return rc; } /** * Write signed long long value to a file according to given base * * @param[in] val Value is to be written * @param[in] base Base for conversion, either 8, 10, or 16 * @param[in] fmt Format string for generation of the path name * @param[in] ... Parameters for format string * * @retval 0 Write was successful * @retval -1 Error while writing file */ int util_file_write_ll(long long val, int base, const char *fmt, ...) { char *str, path[PATH_MAX]; va_list ap; int rc; /* Construct the file name */ UTIL_VSPRINTF(path, fmt, ap); switch (base) { case 8: util_asprintf(&str, "%llo", val); break; case 10: util_asprintf(&str, "%lld", val); break; case 16: util_asprintf(&str, "%llx", val); break; default: util_panic("Invalid base: %d\n", base); } rc = file_puts(str, path); free(str); return rc; } /** * Write unsigned long value to a file according to given base * * @param[in] val Value is to be written * @param[in] base Base for conversion, either 8, 10, or 16 * @param[in] fmt Format string for generation of the path name * @param[in] ... Parameters for format string * * @retval 0 Write was successful * @retval -1 Error while writing file */ int util_file_write_ul(unsigned long val, int base, const char *fmt, ...) { char *str, path[PATH_MAX]; va_list ap; int rc; /* Construct the file name */ UTIL_VSPRINTF(path, fmt, ap); switch (base) { case 8: util_asprintf(&str, "%lo", val); break; case 10: util_asprintf(&str, "%lu", val); break; case 16: util_asprintf(&str, "%lx", val); break; default: util_panic("Invalid base: %d\n", base); } rc = file_puts(str, path); free(str); return rc; } /** * Write unsigned long long value to a file according to given base * * @param[in] val Value is to be written * @param[in] base Base for conversion, either 8, 10, or 16 * @param[in] fmt Format string for generation of the path name * @param[in] ... Parameters for format string * * @retval 0 Write was successful * @retval -1 Error while writing file */ int util_file_write_ull(unsigned long long val, int base, const char *fmt, ...) { char *str, path[PATH_MAX]; va_list ap; int rc; /* Construct the file name */ UTIL_VSPRINTF(path, fmt, ap); switch (base) { case 8: util_asprintf(&str, "%llo", val); break; case 10: util_asprintf(&str, "%llu", val); break; case 16: util_asprintf(&str, "%llx", val); break; default: util_panic("Invalid base: %d\n", base); } rc = file_puts(str, path); free(str); return rc; } /** * Read a file and convert it to signed int according to given base * * @param[out] val Buffer for value * @param[in] base Base for conversion, either 8, 10, or 16 * @param[in] fmt Format string for generation of the path name * @param[in] ... Parameters for format string * * @retval 0 Integer has been read correctly * @retval -1 Error while reading file */ int util_file_read_i(int *val, int base, const char *fmt, ...) { char path[PATH_MAX], buf[512]; va_list ap; int count; /* Construct the file name */ UTIL_VSPRINTF(path, fmt, ap); if (file_gets(buf, sizeof(buf), path)) return -1; switch (base) { case 8: count = sscanf(buf, "%do", val); break; case 10: count = sscanf(buf, "%dd", val); break; case 16: count = sscanf(buf, "%dx", val); break; default: util_panic("Invalid base: %d\n", base); } return (count == 1) ? 0 : -1; } /** * Read a file and convert it to signed long according to given base * * @param[out] val Buffer for value * @param[in] base Base for conversion, either 8, 10, or 16 * @param[in] fmt Format string for generation of the path name * @param[in] ... Parameters for format string * * @retval 0 Long integer has been read correctly * @retval -1 Error while reading file */ int util_file_read_l(long *val, int base, const char *fmt, ...) { char path[PATH_MAX], buf[512]; va_list ap; int count; /* Construct the file name */ UTIL_VSPRINTF(path, fmt, ap); if (file_gets(buf, sizeof(buf), path)) return -1; switch (base) { case 8: count = sscanf(buf, "%lo", val); break; case 10: count = sscanf(buf, "%ld", val); break; case 16: count = sscanf(buf, "%lx", val); break; default: util_panic("Invalid base: %d\n", base); } return (count == 1) ? 0 : -1; } /** * Read a file and convert it to signed long long according to given base * * @param[out] val Buffer for value * @param[in] base Base for conversion, either 8, 10, or 16 * @param[in] fmt Format string for generation of the path name * @param[in] ... Parameters for format string * * @retval 0 Long integer has been read correctly * @retval -1 Error while reading file */ int util_file_read_ll(long long *val, int base, const char *fmt, ...) { char path[PATH_MAX], buf[512]; va_list ap; int count; /* Construct the file name */ UTIL_VSPRINTF(path, fmt, ap); if (file_gets(buf, sizeof(buf), path)) return -1; switch (base) { case 8: count = sscanf(buf, "%llo", val); break; case 10: count = sscanf(buf, "%lld", val); break; case 16: count = sscanf(buf, "%llx", val); break; default: util_panic("Invalid base: %d\n", base); } return (count == 1) ? 0 : -1; } /** * Read a file and convert it to unsigned int according to given base * * @param[out] val Buffer for value * @param[in] base Base for conversion, either 8, 10, or 16 * @param[in] fmt Format string for generation of the path name * @param[in] ... Parameters for format string * * @retval 0 Integer has been read correctly * @retval -1 Error while reading file */ int util_file_read_ui(unsigned int *val, int base, const char *fmt, ...) { char path[PATH_MAX], buf[512]; va_list ap; int count; /* Construct the file name */ UTIL_VSPRINTF(path, fmt, ap); if (file_gets(buf, sizeof(buf), path)) return -1; switch (base) { case 8: count = sscanf(buf, "%uo", val); break; case 10: count = sscanf(buf, "%uu", val); break; case 16: count = sscanf(buf, "%ux", val); break; default: util_panic("Invalid base: %d\n", base); } return (count == 1) ? 0 : -1; } /** * Read a file and convert it to unsigned long according to given base * * @param[out] val Buffer for value * @param[in] base Base for conversion, either 8, 10, or 16 * @param[in] fmt Format string for generation of the path name * @param[in] ... Parameters for format string * * @retval 0 Long integer has been read correctly * @retval -1 Error while reading file */ int util_file_read_ul(unsigned long *val, int base, const char *fmt, ...) { char path[PATH_MAX], buf[512]; va_list ap; int count; /* Construct the file name */ UTIL_VSPRINTF(path, fmt, ap); if (file_gets(buf, sizeof(buf), path)) return -1; switch (base) { case 8: count = sscanf(buf, "%lo", val); break; case 10: count = sscanf(buf, "%lu", val); break; case 16: count = sscanf(buf, "%lx", val); break; default: util_panic("Invalid base: %d\n", base); } return (count == 1) ? 0 : -1; } /** * Read a file and convert it to unsigned long long according to given base * * @param[out] val Buffer for value * @param[in] base Base for conversion, either 8, 10, or 16 * @param[in] fmt Format string for generation of the path name * @param[in] ... Parameters for format string * * @retval 0 Long integer has been read correctly * @retval -1 Error while reading file */ int util_file_read_ull(unsigned long long *val, int base, const char *fmt, ...) { char path[PATH_MAX], buf[512]; va_list ap; int count; /* Construct the file name */ UTIL_VSPRINTF(path, fmt, ap); if (file_gets(buf, sizeof(buf), path)) return -1; switch (base) { case 8: count = sscanf(buf, "%llo", val); break; case 10: count = sscanf(buf, "%llu", val); break; case 16: count = sscanf(buf, "%llx", val); break; default: util_panic("Invalid base: %d\n", base); } return (count == 1) ? 0 : -1; } /** * Read a file and convert it according to format string * * @param[in] path File name to read * @param[in] fmt Format string for parsing the content * @param[out] ... Parameters for format string * * @retval != -1 Number of values parsed correctly * @retval -1 Error while reading file */ int util_file_read_va(const char *path, const char *fmt, ...) { char buf[512]; va_list ap; int ret; if (file_gets(buf, sizeof(buf), path)) return -1; va_start(ap, fmt); ret = vsscanf(buf, fmt, ap); va_end(ap); if (ret == EOF) return -1; return ret; } libzpc-1.3.0/src/zkey/lib/util_file.h000066400000000000000000000024061475140344100174470ustar00rootroot00000000000000/** * @defgroup util_file_h util_file: File read/write interface * @{ * @brief Read and write files * * Copyright IBM Corp. 2016, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef LIB_UTIL_FILE_H #define LIB_UTIL_FILE_H int util_file_read_line(char *str, size_t size, const char *fmt, ...); int util_file_read_i(int *val, int base, const char *fmt, ...); int util_file_read_l(long *val, int base, const char *fmt, ...); int util_file_read_ll(long long *val, int base, const char *fmt, ...); int util_file_read_ui(unsigned int *val, int base, const char *fmt, ...); int util_file_read_ul(unsigned long *val, int base, const char *fmt, ...); int util_file_read_ull(unsigned long long *val, int base, const char *fmt, ...); int util_file_write_s(const char *str, const char *fmt, ...); int util_file_write_l(long val, int base, const char *fmt, ...); int util_file_write_ll(long long val, int base, const char *fmt, ...); int util_file_write_ul(unsigned long val, int base, const char *fmt, ...); int util_file_write_ull(unsigned long long val, int base, const char *fmt, ...); int util_file_read_va(const char *path, const char *fmt, ...); #endif /** LIB_UTIL_FILE_H @} */ libzpc-1.3.0/src/zkey/lib/util_libc.c000066400000000000000000000122211475140344100174300ustar00rootroot00000000000000/* * util - Utility function library * * Handle standard errors for libc functions * * Copyright IBM Corp. 2016, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include #include #include #include #include "lib/util_base.h" #include "lib/util_libc.h" #include "lib/util_panic.h" /* * Return size as string of largest unit, e.g. 1025 = "1 KiB" */ static void format_size(char *str, size_t size) { static const char * const unit_vec[] = {"byte", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}; unsigned int i; for (i = 0; i < ARRAY_SIZE(unit_vec); i++) { if (size / 1024 == 0) { sprintf(str, "%zu %s", size, unit_vec[i]); return; } size /= 1024; } sprintf(str, "huge"); } static void __util_oom(const char *func, const char *file, int line, size_t size) { char size_str[256]; fprintf(stderr, "%s: Failed to allocate memory", program_invocation_short_name); if (size > 0) { format_size(size_str, size); fprintf(stderr, " (%s)", size_str); } fprintf(stderr, " at %s:%d %s()\n", file, line, func); exit(EXIT_FAILURE); } /* * Allocate memory or exit in case of failure */ void *__util_malloc(const char *func, const char *file, int line, size_t size) { void *buf; buf = malloc(size); if (buf == NULL) __util_oom(func, file, line, size); return buf; } /* * Allocate zero-initialized memory or exit in case of failure */ void *__util_zalloc(const char *func, const char *file, int line, size_t size) { void *buf = __util_malloc(func, file, line, size); memset(buf, 0, size); return buf; } /* * Re-allocate memory or exit in case of failure */ void *__util_realloc(const char *func, const char *file, int line, void *ptr, size_t size) { void *buf; buf = realloc(ptr, size); if (buf == NULL) __util_oom(func, file, line, size); return buf; } /* * Duplicate a string buffer or exit in case of failure */ void *__util_strdup(const char *func, const char *file, int line, const char *str) { void *buf = strdup(str); if (buf == NULL) __util_oom(func, file, line, strlen(str) + 1); return buf; } /** * Concatenate two strings or exit in case of failure * * The first string \a str1 is resized and a copy of the second * string \a str2 is appended to it. * * Therefore the first string \a str1 must either have been allocated * using malloc(), calloc(), or realloc() or must be NULL. * * @param[in] str1 Pointer to first string to concatenate, which * becomes invalid * @param[in] str2 Constant pointer to second string to concatenate * * @returns Pointer to concatenated string */ char *util_strcat_realloc(char *str1, const char *str2) { char *buf; if (str1) { buf = util_realloc(str1, strlen(str1) + strlen(str2) + 1); strcat(buf, str2); } else { buf = util_strdup(str2); } return buf; } /** * Convert string to uppercase * * String \a str is converted to uppercase * * @param[in,out] str String to convert */ void util_str_toupper(char *str) { int i; for (i = 0; str[i] != '\0'; i++) str[i] = toupper(str[i]); } /* * Print to newly allocated string or exit in case of failure */ int __util_vasprintf(const char *func, const char *file, int line, char **strp, const char *fmt, va_list ap) { int rc; rc = vasprintf(strp, fmt, ap); if (rc == -1) __util_oom(func, file, line, 0); return rc; } /* * Print to newly allocated string or exit in case of failure */ int __util_asprintf(const char *func, const char *file, int line, char **strp, const char *fmt, ...) { va_list ap; int rc; va_start(ap, fmt); rc = __util_vasprintf(func, file, line, strp, fmt, ap); va_end(ap); return rc; } /* * Print to string buffer or exit in case of failure */ int __util_vsprintf(const char *func, const char *file, int line, char *str, const char *fmt, va_list ap) { int rc; rc = vsprintf(str, fmt, ap); if (rc == -1) __util_assert("rc != -1", func, file, line, rc != -1, "Could not format string\n"); return rc; } /** * Strip leading and trailing spaces from string * * Remove string \a s leading and trailing spaces * * @param[in,out] s String to manipulate * * @returns Pointer to first non-space character in string \a s */ char *util_strstrip(char *s) { size_t size; char *end; size = strlen(s); if (!size) return s; end = s + size - 1; while (end >= s && isspace(*end)) end--; *(end + 1) = '\0'; while (*s && isspace(*s)) s++; return s; } /** * Copy \a src to buffer \a dest of size \a size. At most size - 1 * chars will be copied. \a dest will always be NUL terminated. * * Note: If the return value is greater than or equal to size truncation * occurred. * * @param[in] dest Destination buffer * @param[in] src Source string * @param[in] size Size of destination buffer * * @returns strlen Length of \a src string */ size_t util_strlcpy(char *dest, const char *src, size_t size) { size_t str_len = strlen(src); size_t len; if (size) { len = MIN(size - 1, str_len); memcpy(dest, src, len); dest[len] = '\0'; } return str_len; } libzpc-1.3.0/src/zkey/lib/util_libc.h000066400000000000000000000075021475140344100174430ustar00rootroot00000000000000/** * @defgroup util_libc_h util_libc: Libc wrapper interface * @{ * @brief Handle standard errors for libc functions * * Copyright IBM Corp. 2016, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef LIB_UTIL_LIBC_H #define LIB_UTIL_LIBC_H #include #ifdef __cplusplus extern "C" { #endif /** * Allocate memory or panic in case of failure * * @param[in] size Number of bytes to be allocated * * @returns Pointer to memory buffer created with malloc() */ #define util_malloc(size) \ __util_malloc(__func__, __FILE__, __LINE__, size) void *__util_malloc(const char *func, const char *file, int line, size_t size); /** * Allocate zero-initialized memory or panic in case of failure * * @param[in] size Number of bytes to be allocated * * @returns Pointer to memory buffer created with calloc() */ #define util_zalloc(size) \ __util_zalloc(__func__, __FILE__, __LINE__, size) void *__util_zalloc(const char *func, const char *file, int line, size_t size); /** * Re-allocate memory or exit in case of failure * * @param[in] ptr Pointer ot old memory buffer * @param[in] size Number of bytes to be allocated * * @returns Pointer to memory buffer created with realloc() */ #define util_realloc(ptr, size) \ __util_realloc(__func__, __FILE__, __LINE__, ptr, size) void *__util_realloc(const char *func, const char *file, int line, void *ptr, size_t size); /** * Duplicate a string buffer or exit in case of failure * * @param[in] str String to be duplicated * * @returns Pointer to copied string allocated with malloc() */ #define util_strdup(str) \ __util_strdup(__func__, __FILE__, __LINE__, str) void *__util_strdup(const char *func, const char *file, int line, const char *str); /** * Print to allocated string or exit in case of failure * * @param[in,out] strp Pointer for returned string allocated with malloc() * @param[in] fmt Format string for generation of string * @param[in] ap Parameters for format string * * @returns num Number of formatted characters */ #define util_vasprintf(strp, fmt, ap) \ __util_vasprintf(__func__, __FILE__, __LINE__, strp, fmt, ap) #define UTIL_VASPRINTF(strp, fmt, ap) \ do { \ va_start(ap, fmt); \ util_vasprintf(strp, fmt, ap); \ va_end(ap); \ } while (0) int __util_vasprintf(const char *func, const char *file, int line, char **strp, const char *fmt, va_list ap); /** * Print to newly allocated string or exit in case of failure * * @param[in,out] strp Pointer for returned string allocated with malloc() * @param[in] ... Format string and parameters for format string * * @returns num Number of formatted characters */ #define util_asprintf(strp, ...) \ __util_asprintf(__func__, __FILE__, __LINE__, strp, ##__VA_ARGS__) int __util_asprintf(const char *func, const char *file, int line, char **strp, const char *fmt, ...); /** * Print to string buffer or exit in case of failure * * @param[in] str String buffer * @param[in] fmt Format string for generation of string * @param[in] ap Parameters for format string * * @returns num Number of formatted characters */ #define util_vsprintf(str, fmt, ap) \ __util_vsprintf(__func__, __FILE__, __LINE__, str, fmt, ap) #define UTIL_VSPRINTF(str, fmt, ap) \ do { \ va_start(ap, fmt); \ util_vsprintf(str, fmt, ap); \ va_end(ap); \ } while (0) int __util_vsprintf(const char *func, const char *file, int line, char *str, const char *fmt, va_list ap); char *util_strcat_realloc(char *str1, const char *str2); void util_str_toupper(char *str); char *util_strstrip(char *s); size_t util_strlcpy(char *dest, const char *src, size_t size); #ifdef __cplusplus } #endif #endif /** LIB_UTIL_LIBC_H @} */ libzpc-1.3.0/src/zkey/lib/util_panic.c000066400000000000000000000060041475140344100176130ustar00rootroot00000000000000/* * util - Utility function library * * Collect FFDC data for unexpected errors * * Copyright IBM Corp. 2016, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "debug.h" #include #include #include #include #include #include #include "lib/util_base.h" #include "lib/util_panic.h" /* * Obtain a backtrace and print it to stderr * * To get symbols, compile the code with "-rdynamic". */ static void print_backtrace(void) { void *array[256]; size_t i, size; char **strings; fprintf(stderr, "Backtrace:\n\n"); size = backtrace(array, ARRAY_SIZE(array)); strings = backtrace_symbols(array, size); if (strings == NULL) { fprintf(stderr, " Could not obtain backtrace (ENOMEM)\n"); return; } for (i = 0; i < size; i++) fprintf(stderr, " %s\n", strings[i]); free(strings); } /* * Check for core ulimit */ static void ulimit_core_check(void) { struct rlimit limit; if (getrlimit(RLIMIT_CORE, &limit) != 0) return; if (limit.rlim_cur != 0) return; fprintf(stderr, "Core dump size is zero. To get a full core dump use 'ulimit -c unlimited'.\n"); } /* * Print FFDC data and then abort */ static void panic_finish(const char *func, const char *file, int line, const char *fmt, va_list ap) { /* Write panic error string */ fprintf(stderr, "\n"); fprintf(stderr, "Error string:\n"); fprintf(stderr, "\n"); fprintf(stderr, " "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); /* Write file, line number, and function name */ fprintf(stderr, "Location:\n\n"); fprintf(stderr, " %s:%d: %s()\n", file, line, func); fprintf(stderr, "\n"); /* Print the function backtrace */ print_backtrace(); fprintf(stderr, "\n"); ulimit_core_check(); fprintf(stderr, "----------------------------------------------------------------------->8-----\n"); abort(); } /* * Do panic processing if the assumption is not true */ void __util_assert(const char *assertion_str, const char *func, const char *file, int line, int assumption, const char *fmt, ...) { va_list ap; if (assumption || debug == 0) return; va_start(ap, fmt); fprintf(stderr, "---8<-------------------------------------------------------------------------\n"); fprintf(stderr, "ASSERTION FAILED: The application terminated due to an internal or OS error\n"); fprintf(stderr, "\n"); fprintf(stderr, "The following assumption was *not* true:\n"); fprintf(stderr, "\n"); fprintf(stderr, " %s\n", assertion_str); panic_finish(func, file, line, fmt, ap); } /* * Do panic processing */ void __noreturn __util_panic(const char *func, const char *file, int line, const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "---8<-------------------------------------------------------------------------\n"); fprintf(stderr, "PANIC: The application terminated due to an unrecoverable error\n"); panic_finish(func, file, line, fmt, ap); while(1); } libzpc-1.3.0/src/zkey/lib/util_panic.h000066400000000000000000000024451475140344100176250ustar00rootroot00000000000000/** * @defgroup util_panic_h util_panic: Panic interface * @{ * @brief Collect FFDC data for unexpected errors * * Copyright IBM Corp. 2016, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef LIB_UTIL_PANIC_H #define LIB_UTIL_PANIC_H #include "zt_common.h" /** * Write message, print backtrace and then call the abort() function * * @param[in] ... Format string and parameters describing the panic reason */ #define util_panic(...) \ __util_panic(__func__, __FILE__, __LINE__, ##__VA_ARGS__) void __noreturn __util_panic(const char *func, const char *file, int line, const char *fmt, ...); /** * Ensure that assumption is not true, otherwise panic * * Example: util_assert(ptr == NULL, "The ptr must be NULL, but is %p", ptr) * * @param[in] assumption This assumption has to be true * @param[in] ... Format string and parameters describing the assumption */ #define util_assert(assumption, ...) \ __util_assert(#assumption, __func__, __FILE__, __LINE__, \ assumption, ##__VA_ARGS__) void __util_assert(const char *assertion_string, const char *func, const char *file, int line, int assumption, const char *fmt, ...); #endif /** LIB_UTIL_PANIC_H @} */ libzpc-1.3.0/src/zkey/lib/util_part.c000066400000000000000000000162011475140344100174670ustar00rootroot00000000000000/* * util - Utility function library * * Partition detection functions * * Copyright IBM Corp. 2013, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include #include #include #include #include #include #include #include "lib/util_part.h" #define GPT_SIGNATURE 0x4546492050415254ULL /* EFI PART */ #define MBR_SIGNATURE 0x55aa #define MBR_PART_TYPE_DOS_EXT 0x05 /* DOS extended partition */ #define MBR_PART_TYPE_WIN98_EXT 0x0f /* Windows 98 extended partition */ #define MBR_PART_TYPE_LINUX_EXT 0x85 /* Linux extended partition */ #define MBR_PART_TYPE_GPT 0xee /* GPT partition */ #define MBR_EXT_PART_NUM_FIRST 5 /* Partition number for first logical vol */ /* * MBR/MSDOS partition entry */ struct mbr_part_entry { uint8_t status; uint8_t chs_start[3]; uint8_t type; uint8_t chs_end[3]; uint32_t blk_start; uint32_t blk_cnt; } __attribute__((packed)); /* * Master Boot Record (MBR) */ struct mbr { uint8_t reserved[0x1be]; struct mbr_part_entry part_entry_vec[4]; uint16_t signature; } __attribute__((packed)); /* * GUID Partition Table (GPT) header */ struct gpt { uint64_t signature; uint32_t version; uint32_t hdr_size; uint32_t hdr_crc; uint32_t reserved1; uint64_t blk_cur; uint64_t blk_back; uint64_t blk_first; uint64_t blk_last; uint8_t guid[16]; uint64_t part_tab_blk_start; uint32_t part_tab_cnt; uint32_t part_tab_entry_size; uint32_t part_tab_crc; } __attribute__((packed)); /* * GPT partition entry */ struct gpt_part_entry { uint8_t type[16]; uint8_t guid[16]; uint64_t blk_start; uint64_t blk_end; uint64_t attr; char name[72]; } __attribute__((packed)); /* * Check for extended partition */ static int mbr_part_is_ext(uint8_t type) { if ((type == MBR_PART_TYPE_DOS_EXT) || (type == MBR_PART_TYPE_WIN98_EXT) || (type == MBR_PART_TYPE_LINUX_EXT)) return 1; return 0; } /* * Check if disk has a classic MBR partion table */ static int mbr_table_valid(struct mbr *mbr) { return mbr->signature == MBR_SIGNATURE; } /* * Search partition in logical volumes of an extended partition */ static int mbr_table_ext_search(int fh, size_t blk_start_mbr, size_t blk_start, size_t blk_cnt, size_t blk_size, int part_num) { size_t start, cnt, start_next; struct mbr mbr; /* Read MBR for logical volume */ if (lseek(fh, blk_start_mbr * blk_size, SEEK_SET) == (off_t)-1) return -1; if (read(fh, &mbr, sizeof(mbr)) == -1) return -1; /* Check for invalid MBR or last entry */ if (mbr.signature != MBR_SIGNATURE) return -1; if (mbr.part_entry_vec[0].blk_start == 0) return -1; /* First entry contains a relative offset for current logical volume */ start = blk_start_mbr + le32toh(mbr.part_entry_vec[0].blk_start); cnt = le32toh(mbr.part_entry_vec[0].blk_cnt); if ((start == blk_start) && (cnt == blk_cnt)) return part_num; /* Second entry contains relative offset for next logical volume */ start_next = le32toh(mbr.part_entry_vec[1].blk_start); if (start_next == 0) return 0; start_next += blk_start_mbr; /* Recursively search for next logical volume in chain */ return mbr_table_ext_search(fh, start_next, blk_start, blk_cnt, blk_size, part_num + 1); } /* * Search partition in MBR partition table */ static int mbr_table_search(int fh, struct mbr *mbr, size_t blk_start, size_t blk_cnt, size_t blk_size, int *part_ext) { int part_num_ext, part_num; size_t start, cnt; uint8_t type; for (part_num = 1; part_num <= 4; part_num++) { type = mbr->part_entry_vec[part_num - 1].type; start = le32toh(mbr->part_entry_vec[part_num - 1].blk_start); cnt = le32toh(mbr->part_entry_vec[part_num - 1].blk_cnt); if (start == 0) /* Empty slot */ continue; /* * The kernel sets count for extended partitions explicitly. * Therefore we do not check count here. */ if (mbr_part_is_ext(type) && (start == blk_start)) { *part_ext = 1; return part_num; } if ((start == blk_start) && (cnt == blk_cnt)) return part_num; if (!mbr_part_is_ext(type)) continue; part_num_ext = mbr_table_ext_search(fh, start, blk_start, blk_cnt, blk_size, MBR_EXT_PART_NUM_FIRST); if (part_num_ext != 0) return part_num_ext; } return 0; } /* * Search partition in GPT partition table */ static int gpt_table_search(int fh, struct gpt *gpt, size_t blk_start, size_t blk_cnt, size_t blk_size) { size_t start, end, part_tab_blk_start, blk_end; uint32_t part_tab_cnt, part_tab_entry_size; struct gpt_part_entry *part_entry; unsigned int part_num; blk_end = blk_start + blk_cnt - 1; part_tab_entry_size = le32toh(gpt->part_tab_entry_size); part_tab_cnt = le32toh(gpt->part_tab_cnt); part_tab_blk_start = le64toh(gpt->part_tab_blk_start); if (lseek(fh, part_tab_blk_start * blk_size, SEEK_SET) == (off_t)-1) return -1; for (part_num = 1; part_num <= part_tab_cnt; part_num++) { char buf[part_tab_entry_size]; part_entry = (struct gpt_part_entry *) buf; if (read(fh, buf, sizeof(buf)) == -1) return -1; start = le64toh(part_entry->blk_start); end = le64toh(part_entry->blk_end); if (start == 0) /* Empty slot */ continue; if ((start == blk_start) && (end == blk_end)) return part_num; } return 0; } /* * Check if disk has a GPT partition table */ static int gpt_table_valid(struct gpt *gpt, struct mbr *mbr) { int cnt, part_num; uint32_t start; uint8_t type; if (gpt->signature != GPT_SIGNATURE) return 0; /* Check for protective MBR (one reserved GPT partition) */ for (part_num = 1, cnt = 0; part_num <= 4; part_num++) { start = le32toh(mbr->part_entry_vec[part_num - 1].blk_start); type = mbr->part_entry_vec[part_num - 1].type; if (!start) continue; if (type != MBR_PART_TYPE_GPT) return 0; if (++cnt > 1) return 0; } return 1; } /* * Search for partition with given start block and count * * Return partition number when found, 0 when not found, and on error -1 * Set "part_ext" to 1 for extended partitions otherwise to 0. */ int util_part_search_fh(int fh, size_t blk_start, size_t blk_cnt, size_t blk_size, int *part_ext) { struct gpt gpt; struct mbr mbr; if (lseek(fh, 0, SEEK_SET) == (off_t)-1) return -1; if (read(fh, &mbr, sizeof(mbr)) == -1) return -1; if (lseek(fh, blk_size, SEEK_SET) == (off_t)-1) return -1; if (read(fh, &gpt, sizeof(gpt)) == -1) return -1; *part_ext = 0; if (gpt_table_valid(&gpt, &mbr)) return gpt_table_search(fh, &gpt, blk_start, blk_cnt, blk_size); if (mbr_table_valid(&mbr)) return mbr_table_search(fh, &mbr, blk_start, blk_cnt, blk_size, part_ext); return -1; } /* * Search for partition with given start block and count * * Return partition number when found, 0 when not found, and on error -1 * Set "part_ext" to 1 for extended partitions otherwise to 0. */ int util_part_search(const char *device, size_t blk_start, size_t blk_cnt, size_t blk_size, int *part_ext) { int rc, fh; fh = open(device, O_RDONLY); if (fh == -1) return -1; rc = util_part_search_fh(fh, blk_start, blk_cnt, blk_size, part_ext); close(fh); return rc; } libzpc-1.3.0/src/zkey/lib/util_part.h000066400000000000000000000010451475140344100174740ustar00rootroot00000000000000/* * util - Utility function library * * Partition detection functions * * Copyright IBM Corp. 2013, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef LIB_UTIL_PART_H #define LIB_UTIL_PART_H int util_part_search(const char *dev, size_t blk_start, size_t blk_cnt, size_t blk_size, int *ext_part); int util_part_search_fh(int fh, size_t blk_start, size_t blk_cnt, size_t blk_size, int *ext_part); #endif /* LIB_UTIL_PART_H */ libzpc-1.3.0/src/zkey/lib/util_path.c000066400000000000000000000126401475140344100174600ustar00rootroot00000000000000/* * util - Utility function library * * Work with paths * * Copyright IBM Corp. 2016, 2019 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include #include #include #include #include "lib/util_base.h" #include "lib/util_libc.h" #include "lib/util_path.h" #include "lib/util_prg.h" /* * Verify that directory exists */ static void verify_dir(const char *dir) { struct stat sb; int rc; rc = stat(dir, &sb); if (rc < 0) err(EXIT_FAILURE, "Could not access directory: %s", dir); if (!S_ISDIR(sb.st_mode)) errx(EXIT_FAILURE, "Is not a directory: %s", dir); } /* * Return sysfs mount point * * The caller must free the memory for mount_point. */ static void sys_mount_point(char **mount_point) { char *dir; /* Check the environment variable */ dir = secure_getenv("SYSFS_ROOT"); if (dir) *mount_point = util_strdup(dir); else *mount_point = util_strdup("/sys"); verify_dir(*mount_point); } /** * Construct a sysfs path * * The arguments of the function are used to specify a subdirectory under * sysfs root. * * @param[in] fmt Format string for path * @param[in] ... Variable arguments for format string * * @returns Allocated path */ char *util_path_sysfs(const char *fmt, ...) { char *path, *fmt_path, *sysfs; va_list ap; va_start(ap, fmt); util_vasprintf(&fmt_path, fmt, ap); va_end(ap); sys_mount_point(&sysfs); /* Format and return full sysfs path */ util_asprintf(&path, "%s/%s", sysfs, fmt_path); free(fmt_path); free(sysfs); return path; } /** * Test if path exists and is readable * * This function has the same semantics as "-r path" in bash. * * @param[in] fmt Format string for path to test * @param[in] ... Variable arguments for format string * * @returns true Path exists and is readable * false Otherwise */ bool util_path_is_readable(const char *fmt, ...) { va_list ap; char *path; bool rc; UTIL_VASPRINTF(&path, fmt, ap); rc = access(path, R_OK) == 0; free(path); return rc; } /** * Test if path exists and is writable * * This function has the same semantics as "-w path" in bash. * * @param[in] fmt Format string for path to test * @param[in] ... Variable arguments for format string * * @returns true Path exists and is writable * false Otherwise */ bool util_path_is_writable(const char *fmt, ...) { va_list ap; char *path; bool rc; UTIL_VASPRINTF(&path, fmt, ap); rc = access(path, W_OK) == 0; free(path); return rc; } /** * Test if path exists and is a regular file * * This function has the same semantics as "-f path" in bash. * * @param[in] fmt Format string for path to test * @param[in] ... Variable arguments for format string * * @returns true Path exists and is a regular file * false Otherwise */ bool util_path_is_reg_file(const char *fmt, ...) { bool rc = false; struct stat sb; va_list ap; char *path; UTIL_VASPRINTF(&path, fmt, ap); if (stat(path, &sb) == 0) rc = S_ISREG(sb.st_mode); free(path); return rc; } /** * Test if path exists and is a directory * * This function has the same semantics as "-d path" in bash. * * @param[in] fmt Format string for path to test * @param[in] ... Variable arguments for format string * * @returns true Path exists and is a directory * false Otherwise */ bool util_path_is_dir(const char *fmt, ...) { bool rc = false; struct stat sb; va_list ap; char *path; UTIL_VASPRINTF(&path, fmt, ap); if (stat(path, &sb) == 0) rc = S_ISDIR(sb.st_mode); free(path); return rc; } /** * Test if path to directory or file exists * * This function has the same semantics as "-e path" in bash. * * @param[in] fmt Format string for path to test * @param[in] ... Variable arguments for format string * * @returns true Path exists * false Otherwise */ bool util_path_exists(const char *fmt, ...) { va_list ap; char *path; bool rc; UTIL_VASPRINTF(&path, fmt, ap); rc = access(path, F_OK) == 0; free(path); return rc; } /** * Test if path exists, is a regular file, and permission is read-only * * @param[in] fmt Format string for path to test * @param[in] ... Variable arguments for format string * * @returns true Path exists, is a regular file, and permission does * not allow any write but allows read * false Otherwise */ bool util_path_is_readonly_file(const char *fmt, ...) { bool rc = false; struct stat sb; va_list ap; char *path; UTIL_VASPRINTF(&path, fmt, ap); if (stat(path, &sb) == 0) { rc = S_ISREG(sb.st_mode) && (sb.st_mode & 0222) == 0 && (sb.st_mode & 0444) != 0; } free(path); return rc; } /** * Test if path exists, is a regular file, and permission is write-only * * @param[in] fmt Format string for path to test * @param[in] ... Variable arguments for format string * * @returns true Path exists, is a regular file, and permission does * not allow any read but allows write * false Otherwise */ bool util_path_is_writeonly_file(const char *fmt, ...) { bool rc = false; struct stat sb; va_list ap; char *path; UTIL_VASPRINTF(&path, fmt, ap); if (stat(path, &sb) == 0) { rc = S_ISREG(sb.st_mode) && (sb.st_mode & 0222) != 0 && (sb.st_mode & 0444) == 0; } free(path); return rc; } libzpc-1.3.0/src/zkey/lib/util_path.h000066400000000000000000000014031475140344100174600ustar00rootroot00000000000000/** * @defgroup util_path_h util_path: Path interface * @{ * @brief Work with paths * * Copyright IBM Corp. 2016, 2019 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef LIB_UTIL_PATH_H #define LIB_UTIL_PATH_H #include char *util_path_sysfs(const char *fmt, ...); bool util_path_is_readable(const char *fmt, ...); bool util_path_is_writable(const char *fmt, ...); bool util_path_is_dir(const char *fmt, ...); bool util_path_is_reg_file(const char *fmt, ...); bool util_path_exists(const char *fmt, ...); bool util_path_is_readonly_file(const char *fmt, ...); bool util_path_is_writeonly_file(const char *fmt, ...); #endif /** LIB_UTIL_PATH_H @} */ libzpc-1.3.0/src/zkey/lib/util_prg.c000066400000000000000000000057701475140344100173220ustar00rootroot00000000000000/* * util - Utility function library * * Print standard program messages * * Copyright IBM Corp. 2016, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include "lib/util_base.h" #include "lib/util_prg.h" #include "lib/zt_common.h" /* * Private data */ static struct util_prg_l { const struct util_prg *prg; /* Command used for parsing */ const char *command; } l; /** * Set the current command for command line option processing * * @param[in] command The current command or NULL for no command */ void util_prg_set_command(const char *command) { l.command = command; } /** * Print program usage information for the --help option */ void util_prg_print_help(void) { /* Print usage */ printf("Usage: %s", program_invocation_short_name); if (l.prg->command_args) printf(" %s", l.prg->command_args); printf(" [OPTIONS]"); if (l.prg->args) printf(" %s", l.prg->args); /* Print usage description */ printf("\n\n"); util_print_indented(l.prg->desc, 0); printf("\n"); } /** * Print program version information for the --version option */ void util_prg_print_version(void) { const struct util_prg_copyright *copyright; printf("%s version %s\n", program_invocation_short_name, RELEASE_STRING); copyright = l.prg->copyright_vec; while (copyright->owner) { if (copyright->pub_first == copyright->pub_last) printf("Copyright %s %d\n", copyright->owner, copyright->pub_first); else printf("Copyright %s %d, %d\n", copyright->owner, copyright->pub_first, copyright->pub_last); copyright++; } } /* * Ask user to use the --help option */ void util_prg_print_parse_error(void) { if (l.command) fprintf(stderr, "Try '%s %s --help' for more information.\n", program_invocation_short_name, l.command); else fprintf(stderr, "Try '%s --help' for more information.\n", program_invocation_short_name); } /** * An option has been specified that is not supported * * @param[in] option Option string (short or long) */ void util_prg_print_invalid_option(const char *opt_name) { fprintf(stderr, "%s: Invalid option '%s'\n", program_invocation_short_name, opt_name); util_prg_print_parse_error(); } /** * A required argument for an option is missing * * @param[in] option Option string */ void util_prg_print_required_arg(const char *opt_name) { fprintf(stderr, "%s: Option '%s' requires an argument\n", program_invocation_short_name, opt_name); util_prg_print_parse_error(); } /** * A superfluous invalid positional argument has been specified * * @param[in] arg_name Name of the invalid argument */ void util_prg_print_arg_error(const char *arg_name) { fprintf(stderr, "%s: Invalid argument '%s'\n", program_invocation_short_name, arg_name); util_prg_print_parse_error(); } /** * Initialize the program module * * @param[in] prg Program description */ void util_prg_init(const struct util_prg *prg) { l.prg = prg; } libzpc-1.3.0/src/zkey/lib/util_prg.h000066400000000000000000000025761475140344100173300ustar00rootroot00000000000000/** * @defgroup util_prg_h util_prg: Program interface * @{ * @brief Print standard program messages * * Copyright IBM Corp. 2016, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef LIB_UTIL_PRG_H #define LIB_UTIL_PRG_H #include #include #include #include #include struct util_prg_copyright { /** Name of the copyright owner, e.g. IBM */ const char *owner; /** Year of first publishing */ int pub_first; /** Year of last major changes */ int pub_last; }; /** * @brief Coypright end marker */ #define UTIL_PRG_COPYRIGHT_END {NULL, 0, 0} /** * Program description */ struct util_prg { /** Description for help */ const char *desc; /** Command arguments in front of other options */ const char *command_args; /** Positional arguments */ const char *args; /** Copyright list */ struct util_prg_copyright copyright_vec[]; }; void util_prg_init(const struct util_prg *prg); void util_prg_set_command(const char *command); void util_prg_print_parse_error(void); void util_prg_print_required_arg(const char *option); void util_prg_print_invalid_option(const char *option); void util_prg_print_arg_error(const char *arg_name); void util_prg_print_version(void); void util_prg_print_help(void); #endif /** LIB_UTIL_PRG_H @} */ libzpc-1.3.0/src/zkey/lib/zt_common.h000066400000000000000000000045321475140344100175020ustar00rootroot00000000000000/* * s390-tools/include/zt_common.h * common s390-tools definitions. * * Copyright IBM Corp. 2004, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. * */ #ifndef LIB_ZT_COMMON_H #define LIB_ZT_COMMON_H #include "misc.h" #define STRINGIFY_1(x) #x #define STRINGIFY(x) STRINGIFY_1(x) /* Use this macro to make constant macros usable in both assembler and * C code. * * Usage example: * #define IMAGE_ENTRY _AC(0x10000, UL) */ #ifdef __ASSEMBLER__ #define _AC(X, TYPE) X #else #define _AC(X, TYPE) X##TYPE #endif #ifndef __ASSEMBLER__ #ifdef STATIC_ASSERT #elif defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ >= 5) # define STATIC_ASSERT(test) _Static_assert((test), "(" #test ") failed"); #else # define STATIC_ASSERT(test) #endif #define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1) #define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define RELEASE_STRING STRINGIFY (S390_TOOLS_RELEASE) #define TOOLS_LIBDIR STRINGIFY (S390_TOOLS_LIBDIR) #define TOOLS_SYSCONFDIR STRINGIFY (S390_TOOLS_SYSCONFDIR) #define TOOLS_BINDIR STRINGIFY (S390_TOOLS_BINDIR) #define TOOLS_DATADIR STRINGIFY (S390_TOOLS_DATADIR) #define __noreturn __attribute__((noreturn)) #define __aligned(x) __attribute__((aligned(x))) #define __may_alias __attribute__((may_alias)) #define __section(x) __attribute__((__section__(#x))) #define __noinline __attribute__((__noinline__)) /* The Linux kernel (in stddef.h) and glibc (sys/cdefs.h) define * __always_inline. Therefore undefine it first to allow the headers * to be included first. */ #undef __always_inline #define __always_inline inline __attribute__((always_inline)) #define __pa32(x) ((uint32_t)(unsigned long)(x)) #define __pa(x) ((unsigned long)(x)) #define barrier() __asm__ __volatile__("": : :"memory") #undef MIN #define MIN(x, y) \ ({ \ __typeof__(x) _x = (x); \ __typeof__(y) _y = (y); \ \ _x < _y ? _x : _y; \ }) #undef MAX #define MAX(x, y) \ ({ \ __typeof__(x) _x = (x); \ __typeof__(y) _y = (y); \ \ _x > _y ? _x : _y; \ }) typedef signed long long s64; typedef signed int s32; typedef signed short int s16; typedef signed char s8; #endif /* __ASSEMBLER__ */ #endif /* LIB_ZT_COMMON_H */ libzpc-1.3.0/src/zkey/pkey.c000066400000000000000000000257531475140344100157020ustar00rootroot00000000000000/* * zkey - Generate, re-encipher, and validate secure keys * * Copyright IBM Corp. 2018 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "zpc/error.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lib/util_base.h" #include "lib/util_libc.h" #include "lib/util_panic.h" #include "pkey.h" #include "utils.h" /** * Check if the specified key is a CCA AESDATA key token. * * @param[in] key the secure key token * @param[in] key_size the size of the secure key * * @returns true if the key is an CCA AESDATA token type */ bool is_cca_aes_data_key(const u8 *key, size_t key_size) { struct tokenheader *hdr = (struct tokenheader *)key; if (key == NULL || key_size < AESDATA_KEY_SIZE) return false; if (hdr->type != TOKEN_TYPE_CCA_INTERNAL) return false; if (hdr->version != TOKEN_VERSION_AESDATA) return false; return true; } /** * Check if the specified key is a CCA AESCIPHER key token. * * @param[in] key the secure key token * @param[in] key_size the size of the secure key * * @returns true if the key is an CCA AESCIPHER token type */ bool is_cca_aes_cipher_key(const u8 *key, size_t key_size) { struct aescipherkeytoken *cipherkey = (struct aescipherkeytoken *)key; if (key == NULL || key_size < AESCIPHER_KEY_SIZE_ENCR_V0) return false; if (cipherkey->type != TOKEN_TYPE_CCA_INTERNAL) return false; if (cipherkey->version != TOKEN_VERSION_AESCIPHER) return false; if (cipherkey->length > key_size) return false; if (cipherkey->kms != 0x03) /* key wrapped by master key */ return false; if (cipherkey->kwm != 0x02) /* key wrapped using AESKW */ return false; if (cipherkey->pfv != 0x00 && cipherkey->pfv != 0x01) /* V0 or V1 */ return false; if (cipherkey->adv != 0x01) /* Should have ass. data sect. version 1 */ return false; if (cipherkey->at != 0x02) /* Algorithm: AES */ return false; if (cipherkey->kt != 0x0001) /* Key type: CIPHER */ return false; if (cipherkey->adl != 26) /* Ass. data section length should be 26 */ return false; if (cipherkey->kll != 0) /* Should have no key label */ return false; if (cipherkey->eadl != 0) /* Should have no ext associated data */ return false; if (cipherkey->uadl != 0) /* Should have no user associated data */ return false; if (cipherkey->kufc != 2) /* Should have 2 KUFs */ return false; if (cipherkey->kmfc != 3) /* Should have 3 KMFs */ return false; return true; } /** * Check if the specified key is a CCA ECC key token. * * @param[in] key the secure key token * @param[in] key_size the size of the secure key * * @returns true if the key is an CCA ECC token type */ bool is_cca_ec_key(const u8 *key, size_t key_size) { struct ccakeytoken *cipherkey = (struct ccakeytoken *)key; if (key == NULL || key_size < sizeof(struct ccakeytoken)) return false; if (cipherkey->type != 0x1F) /* internal header */ return false; if (cipherkey->privtok != 0x20) /* private section */ return false; if (cipherkey->key_format != 0x08) /* encrypted internal EC key */ return false; switch (cipherkey->curve_type) { case 0: /* prime */ case 2: /* edwards */ break; default: return false; } switch (cipherkey->p_len) { case 255: /* ed25519 */ case 256: /* p256 */ case 384: /* p384 */ case 521: /* p521 */ case 448: /* ed448 */ break; default: return false; } return true; } /** * Check if the specified EP11 type 6 (TOKVER_EP11_AES_WITH_HEADER) AES key * token is session bound, i.e. has a non-zero session id. * * @param[in] key the type 6 secure key token * @param[in] key_size the size of the secure key * * @returns true if the key is a session-bound type 6 EP11 AES key token */ bool is_session_bound(const u8 *key, size_t key_size) { const unsigned char null_session[32] = { 0, }; if (!is_ep11_aes_key_with_header(key, key_size)) return false; if (memcmp(key + sizeof(struct ep11kblob_header), null_session, sizeof(null_session)) == 0) return false; return true; } /** * Check if the specified key is a type 3 (TOKVER_EP11_AES) EP11 AES key token. * Type 3 keys always have their session id field overlayed by the key token * header, so they cannot contain a valid session id. Let's require that the * 2nd 16 bytes of the session id field are always zero, otherwise consider * the key as corrupted. * * @param[in] key the secure key token * @param[in] key_size the size of the secure key * * @returns true if the key is an EP11 AES token type */ bool is_ep11_aes_key(const u8 *key, size_t key_size) { struct ep11keytoken *ep11key = (struct ep11keytoken *)key; const unsigned char nulls[16] = { 0, }; if (key == NULL || key_size < (EP11_KEY_SIZE - sizeof(ep11key->padding))) return false; if (ep11key->head.type != TOKEN_TYPE_NON_CCA) return false; if (ep11key->head.version != TOKEN_VERSION_EP11_AES) return false; if (ep11key->head.length > key_size) return false; if (ep11key->version != EP11_STRUCT_MAGIC) return false; if (memcmp(key + 16, nulls, 16) != 0) return false; return true; } /* * Check if the specified key is a EP11 AES key token with header. * * @param[in] key the secure key token * @param[in] key_size the size of the secure key * * @returns true if the key is an EP11 AES key token with header */ bool is_ep11_aes_key_with_header(const u8 *key, size_t key_size) { struct ep11kblob_header *hdr = (struct ep11kblob_header *)key; struct ep11keytoken *ep11key = (struct ep11keytoken *)(key + sizeof(struct ep11kblob_header)); if (key_size < (sizeof(struct ep11kblob_header) + EP11_KEY_SIZE - sizeof(ep11key->padding))) return 0; if (hdr->type != TOKEN_TYPE_NON_CCA) return 0; if (hdr->hver != 0x00) return 0; if (hdr->version != TOKVER_EP11_AES_WITH_HEADER) return 0; if (hdr->len > key_size) return 0; if (hdr->len < (sizeof(struct ep11kblob_header) + EP11_KEY_SIZE - sizeof(ep11key->padding))) return 0; if (ep11key->version != EP11_STRUCT_MAGIC) return 0; return 1; } /** * Check if the specified key is an EP11 ECC key token with header * (TOKVER_EP11_ECC_WITH_HEADER). This means we have a 16-byte ep11kblob_header * followed by a ep11keytoken struct. We assume that the blob does not contain * a filled out ep11keytoken header in the session field. * * @param[in] key the secure key token * @param[in] key_size the size of the secure key * * @returns true if the key is an EP11 ECC token type */ bool is_ep11_ec_key_with_header(const u8 *key, size_t key_size) { struct ep11kblob_header *ep11hdr; struct ep11keytoken *ep11key; if (key == NULL || key_size < MIN_EC_BLOB_SIZE || key_size > MAX_EC_BLOB_SIZE) return false; ep11hdr = (struct ep11kblob_header *)key; ep11key = (struct ep11keytoken *)(key + sizeof(struct ep11kblob_header)); if (ep11hdr->version != TOKVER_EP11_ECC_WITH_HEADER) return false; if (ep11key->version != EP11_STRUCT_MAGIC) return false; return true; } /** * Check if the specified key is an XTS type key * * @param[in] key the secure key token * @param[in] key_size the size of the secure key * * @returns true if the key is an XTS key type */ bool is_xts_key(const u8 *key, size_t key_size) { if (is_cca_aes_data_key(key, key_size)) { if (key_size == 2 * AESDATA_KEY_SIZE && is_cca_aes_data_key(key + AESDATA_KEY_SIZE, key_size - AESDATA_KEY_SIZE)) return true; } else if (is_cca_aes_cipher_key(key, key_size)) { if (key_size == 2 * AESCIPHER_KEY_SIZE && is_cca_aes_cipher_key(key + AESCIPHER_KEY_SIZE, key_size - AESCIPHER_KEY_SIZE)) return true; } else if (is_ep11_aes_key(key, key_size)) { if (key_size == 2 * EP11_KEY_SIZE && is_ep11_aes_key(key + EP11_KEY_SIZE, key_size - EP11_KEY_SIZE)) return true; } return false; } /* * Returns list of napqns in apqns that match the mkvp and key type. * Caller takes ownership of apqns. * Returns 0 on success. Otherwise, an appropriate ZPC_ERROR is returned. */ int alloc_apqns_from_mkvp(int pkeyfd, struct pkey_apqn **apqns, size_t *napqns, const unsigned char mkvp[], int type) { struct pkey_apqns4keytype apqns4keytype; int rc; assert(apqns != NULL); assert(napqns != NULL); assert(mkvp != NULL); *apqns = NULL; *napqns = 0; for (;;) { if (*napqns > 0) { *apqns = calloc(*napqns, sizeof(**apqns)); if (*apqns == NULL) { rc = ZPC_ERROR_MALLOC; goto ret; } } memset(&apqns4keytype, 0, sizeof(apqns4keytype)); apqns4keytype.type = type; memcpy(apqns4keytype.cur_mkvp, mkvp, sizeof(apqns4keytype.cur_mkvp)); memcpy(apqns4keytype.alt_mkvp, mkvp, sizeof(apqns4keytype.alt_mkvp)); apqns4keytype.flags = PKEY_FLAGS_MATCH_CUR_MKVP; apqns4keytype.apqns = *apqns; apqns4keytype.apqn_entries = *napqns; rc = ioctl(pkeyfd, PKEY_APQNS4KT, &apqns4keytype); if (rc && (*napqns == 0 || (*napqns > 0 && rc != ENOSPC))) { rc = ZPC_ERROR_IOCTLAPQNS4KT; goto ret; } else if (rc == 0 && apqns4keytype.apqn_entries == 0) { rc = ZPC_ERROR_APQNNOTFOUND; goto ret; } else if (rc == 0 && *napqns > 0) { break; } free(*apqns); *apqns = NULL; *napqns = apqns4keytype.apqn_entries; } rc = 0; ret: return rc; } /* * Some ECC related utility arrays. Array index is the curve's * enumeration from zpc_ec_curve_t. */ const size_t curve2publen[] = { EC_PUBLEN_P256, EC_PUBLEN_P384, EC_PUBLEN_P521, EC_PUBLEN_ED25519, EC_PUBLEN_ED448 }; const size_t curve2privlen[] = { EC_PRIVLEN_P256, EC_PRIVLEN_P384, EC_PRIVLEN_P521, EC_PRIVLEN_ED25519, EC_PRIVLEN_ED448 }; const uint16_t curve2bitlen[] = { EC_BITLEN_P256, EC_BITLEN_P384, EC_BITLEN_P521, EC_BITLEN_ED25519, EC_BITLEN_ED448 }; const size_t curve2siglen[] = { EC_SIGLEN_P256, EC_SIGLEN_P384, EC_SIGLEN_P521, EC_SIGLEN_ED25519, EC_SIGLEN_ED448, }; const size_t curve2puboffset[] = { sizeof(p256_maced_spki_t) - EC_PUBLEN_P256 - EP11_SPKI_MACLEN, sizeof(p384_maced_spki_t) - EC_PUBLEN_P384 - EP11_SPKI_MACLEN, sizeof(p521_maced_spki_t) - EC_PUBLEN_P521 - EP11_SPKI_MACLEN, sizeof(ed25519_maced_spki_t) - EC_PUBLEN_ED25519 - EP11_SPKI_MACLEN, sizeof(ed448_maced_spki_t) - EC_PUBLEN_ED448 - EP11_SPKI_MACLEN, }; const size_t curve2macedspkilen[] = { sizeof(p256_maced_spki_t), sizeof(p384_maced_spki_t), sizeof(p521_maced_spki_t), sizeof(ed25519_maced_spki_t), sizeof(ed448_maced_spki_t), }; const size_t curve2rawspkilen[] = { sizeof(p256_maced_spki_t) - EP11_SPKI_MACLEN, sizeof(p384_maced_spki_t) - EP11_SPKI_MACLEN, sizeof(p521_maced_spki_t) - EP11_SPKI_MACLEN, sizeof(ed25519_maced_spki_t) - EP11_SPKI_MACLEN, sizeof(ed448_maced_spki_t) - EP11_SPKI_MACLEN, }; const u32 curve2pkey_keytype[] = { PKEY_KEYTYPE_ECC_P256, PKEY_KEYTYPE_ECC_P384, PKEY_KEYTYPE_ECC_P521, PKEY_KEYTYPE_ECC_ED25519, PKEY_KEYTYPE_ECC_ED448, }; libzpc-1.3.0/src/zkey/pkey.h000066400000000000000000000413761475140344100157060ustar00rootroot00000000000000/* * zkey - Generate, re-encipher, and validate secure keys * * This header file defines the interface to the pkey kernel module. * It defines a set of IOCTL commands with its associated structures. * * Copyright IBM Corp. 2017, 2018 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef PKEY_H #define PKEY_H #include #include "lib/zt_common.h" #include "cca.h" #include "ep11.h" #define SYSFS_DEVICES_AP "/sys/devices/ap/" /* * Definitions for the /dev/pkey kernel module interface */ struct tokenheader { u8 type; u8 res0[3]; u8 version; u8 res1[3]; } __packed; #define TOKEN_TYPE_NON_CCA 0x00 #define TOKEN_TYPE_CCA_INTERNAL 0x01 /* CCA-Internal token versions */ #define TOKEN_VERSION_AESDATA 0x04 #define TOKEN_VERSION_AESCIPHER 0x05 /* Non-CCA token versions */ #define TOKEN_VERSION_PROTECTED_KEY 0x01 #define TOKEN_VERSION_CLEAR_KEY 0x02 #define TOKEN_VERSION_EP11_AES 0x03 /* Some ECC related constants */ #define EC_PUBLEN_P256 64 #define EC_PUBLEN_P384 96 #define EC_PUBLEN_P521 132 #define EC_PUBLEN_ED25519 32 #define EC_PUBLEN_ED448 57 #define EC_PRIVLEN_P256 32 #define EC_PRIVLEN_P384 48 #define EC_PRIVLEN_P521 66 #define EC_PRIVLEN_ED25519 32 #define EC_PRIVLEN_ED448 57 #define EC_BITLEN_P256 256 #define EC_BITLEN_P384 384 #define EC_BITLEN_P521 521 #define EC_BITLEN_ED25519 255 #define EC_BITLEN_ED448 448 #define EC_SIGLEN_P256 64 #define EC_SIGLEN_P384 96 #define EC_SIGLEN_P521 132 #define EC_SIGLEN_ED25519 64 #define EC_SIGLEN_ED448 114 #define MKVP_LEN_EP11 16 #define MKVP_LEN_CCA 8 struct aesdatakeytoken { u8 type; /* TOKEN_TYPE_INTERNAL (0x01) for internal key token */ u8 res0[3]; u8 version; /* should be TOKEN_VERSION_AESDATA (0x04) */ u8 res1[1]; u8 flag; /* key flags */ u8 res2[1]; u64 mkvp; /* master key verification pattern */ u8 key[32]; /* key value (encrypted) */ u8 cv[8]; /* control vector */ u16 bitsize; /* key bit size */ u16 keysize; /* key byte size */ u8 tvv[4]; /* token validation value */ } __packed; struct aescipherkeytoken { u8 type; /* TOKEN_TYPE_INTERNAL (0x01) for internal key token */ u8 res0; u16 length; /* length of token */ u8 version; /* should be TOKEN_VERSION_CIPHER (0x05) */ u8 res1[3]; u8 kms; /* key material state, should be 0x03 */ u8 kvptype; /* key verification pattern type */ u8 kvp[16]; /* key verification pattern */ u8 kwm; /* key wrapping method, should be 0x02 */ u8 kwh; /* key wrapping hash algorithm */ u8 pfv; /* payload format version, should be 0x00*/ u8 res2; u8 adv; /* associated data section version */ u8 res3; u16 adl; /* associated data length */ u8 kll; /* length of optional key label */ u8 eadl; /* extended associated data length */ u8 uadl; /* user associated data length */ u8 res4; u16 pl; /* payload bit length */ u8 res5; u8 at; /* algorithm type, should be 0x02 (AES) */ u16 kt; /* key type, should be 0x0001 (CIPHER) */ u8 kufc; /* key usage field count */ u16 kuf1; /* key usage field 1 */ u16 kuf2; /* key usage field 2 */ u8 kmfc; /* key management field count */ u16 kmf1; /* key management field 1 */ u16 kmf2; /* key management field 2 */ u16 kmf3; /* key management field 3 */ u8 varpart[80]; /* variable part */ } __packed; struct ccakeytoken { u8 type; /* TOKEN_TYPE_INTERNAL (0x1F) for internal key token */ u8 version; u16 length; u32 reserved1; u8 privtok; /* CCA private key token: 0x20 */ u8 priv_tok_version; u16 priv_tok_len; u8 aeskw; /* secure key: AESKW */ u8 data_sec_hash; /* data section hash */ u16 reserved2; u8 keyusage; u8 curve_type; u8 key_format; /* 0x08 = encrypted internal EC key */ u8 section_version; u16 p_len; u16 associated_data_len1; u8 mkvp[MKVP_LEN_CCA]; u8 opk[48]; /* Object Protection Key (OPK) */ u16 associated_data_len2; u16 formatted_section_len; u8 associated_data_version; u8 key_label_len; u16 associated_data_len3; u16 ext_associated_data_len; u8 user_definable_data_len; u8 curve_type2; u16 p_len2; u8 key_usage_flag; u8 key_format_flag; u8 ad_section_version; u8 reserved3[3]; u8 encr_d[0]; /* followed by encrypted (D) */ } __packed; struct eccpubtoken { u8 id; /* 0x21 = public section */ u8 version; u16 length; u32 reserved1; u8 curve_type; u8 reserved2; u16 p_bitlen; u16 q_len; u8 q[0]; /* followed by variable length q, max 133 bytes */ } __packed; #define EP11_STRUCT_MAGIC 0x1234 /* * Internal used values for the version field of the key header. * Should match to the enum pkey_key_type in pkey.h. */ #define TOKVER_EP11_AES 0x03 /* EP11 AES key blob (old style) */ #define TOKVER_EP11_AES_WITH_HEADER 0x06 /* EP11 AES key blob with hdr */ #define TOKVER_EP11_ECC_WITH_HEADER 0x07 /* EP11 ECC key blob with hdr */ /* 0x08 is reserved for internal use */ #define TOKVER_UV_SECRET 0x09 /* UV retrievable secret */ struct ep11keytoken { union { u8 session[32]; struct { u8 type; /* TOKEN_TYPE_NON_CCA (0x00) */ u8 res0; /* unused */ u16 length; /* length of token */ u8 version; /* TOKEN_VERSION_EP11_AES (0x03) */ u8 res1; /* unused */ u16 keybitlen; /* clear key bit len, 0 for unknown */ } head; }; u8 wkvp[MKVP_LEN_EP11]; /* wrapping key verification pattern */ u64 attr; /* boolean key attributes */ u64 mode; /* mode bits */ u16 version; /* 0x1234, ep11 blob struct version */ u8 iv[14]; u8 encrypted_key_data[144]; u8 mac[32]; u8 padding[64]; } __packed; #define AESDATA_KEY_SIZE sizeof(struct aesdatakeytoken) #define AESCIPHER_KEY_SIZE sizeof(struct aescipherkeytoken) #define EP11_KEY_SIZE sizeof(struct ep11keytoken) #define UV_SECRET_ID_LEN 32 /* Inside view of an UV retrievable secret key token */ struct uvrsecrettoken { u8 type; /* 0x00 - Non-CCA key token */ u8 res0[3]; u8 version; /* 0x09 - UV retrievable secret */ u8 res1[3]; u16 secret_type; /* the secret type as the UV told us */ u16 secret_len; /* length in bytes of the secret */ u8 secret_id[UV_SECRET_ID_LEN]; /* the secret id for this secret */ } __packed; /* * CCA Application Programmer's Guide, AES CIPHER variable-length symmetric * key token: * - Encrypted V0 payload: 120 bytes * - Encrypted V1 payload: 136 bytes */ #define AESCIPHER_KEY_SIZE_ENCR_V0 AESCIPHER_KEY_SIZE - 16 #define AESCIPHER_KEY_SIZE_ENCR_V1 AESCIPHER_KEY_SIZE /* MAX/MIN from zt_common.h produces warnings for variable length arrays */ #define _MIN(a, b) ((a) < (b) ? (a) : (b)) #define _MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN_EC_BLOB_SIZE _MIN(sizeof(struct ccakeytoken), \ sizeof(struct ep11keytoken)) #define MAX_EC_BLOB_SIZE 2048 #define MAX_SECURE_KEY_SIZE _MAX(EP11_KEY_SIZE, \ _MAX(AESDATA_KEY_SIZE, _MAX(AESCIPHER_KEY_SIZE, UV_SECRET_ID_LEN))) #define MIN_SECURE_KEY_SIZE _MIN(EP11_KEY_SIZE, \ _MIN(AESDATA_KEY_SIZE, _MAX(AESCIPHER_KEY_SIZE, UV_SECRET_ID_LEN))) #define MAXPROTKEYSIZE 64 /* a protected key blob may be up to 64 bytes */ /* Struct to hold protected AES key and length info */ struct pkey_protkey { u32 type; /* key type, one of the PKEY_KEYTYPE_AES values */ u32 len; /* bytes actually stored in protkey[] */ u8 protkey[MAXPROTKEYSIZE]; /* the protected key blob */ }; #define MAXECPROTKEYSIZE 112 /* max 80 + 32 bytes for p521 */ struct pkey_ecprotkey { u8 protkey[MAXECPROTKEYSIZE]; /* the EC protected key blob */ }; #define MAX_MACED_SPKI_SIZE sizeof(p521_maced_spki_t) struct pkey_ecpubkey { u32 publen; u8 pubkey[132]; /* max (66,66) for p521 public key (X,Y) value */ u32 spkilen; u8 spki[MAX_MACED_SPKI_SIZE]; }; struct pkey_seckey { u8 seckey[AESDATA_KEY_SIZE]; /* the secure key blob */ }; struct pkey_clrkey { u8 clrkey[32]; /* 16, 24, or 32 byte clear key value */ }; #define PKEY_IOCTL_MAGIC 'p' #define AUTOSELECT 0xFFFF #define PKEYDEVICE "/dev/pkey" #define PKEY_KEYTYPE_AES_128 1 #define PKEY_KEYTYPE_AES_192 2 #define PKEY_KEYTYPE_AES_256 3 #define PKEY_KEYTYPE_ECC 4 #define PKEY_KEYTYPE_ECC_P256 5 #define PKEY_KEYTYPE_ECC_P384 6 #define PKEY_KEYTYPE_ECC_P521 7 #define PKEY_KEYTYPE_ECC_ED25519 8 #define PKEY_KEYTYPE_ECC_ED448 9 /* inside view of a clear key token (type 0x00 version 0x02) */ struct clearkeytoken { u8 type; /* 0x00 for PAES specific key tokens */ u8 res0[3]; u8 version; /* 0x02 for clear key token */ u8 res1[3]; u32 keytype; /* key type, one of the PKEY_KEYTYPE_* values */ u32 len; /* bytes actually stored in clearkey[] */ u8 clearkey[]; /* clear key value */ } __packed; struct pkey_genseck { u16 cardnr; /* in: card to use or FFFF for any */ u16 domain; /* in: domain or FFFF for any */ u32 keytype; /* in: key type to generate */ struct pkey_seckey seckey; /* out: the secure key blob */ }; #define PKEY_GENSECK _IOWR(PKEY_IOCTL_MAGIC, 0x01, struct pkey_genseck) struct pkey_clr2seck { u16 cardnr; /* in: card to use or FFFF for any */ u16 domain; /* in: domain or FFFF for any*/ u32 keytype; /* in: key type to generate */ struct pkey_clrkey clrkey; /* in: the clear key value */ struct pkey_seckey seckey; /* out: the secure key blob */ }; #define PKEY_CLR2SECK _IOWR(PKEY_IOCTL_MAGIC, 0x02, struct pkey_clr2seck) struct pkey_verifykey { struct pkey_seckey seckey; /* in: the secure key blob */ u16 cardnr; /* out: card number */ u16 domain; /* out: domain number */ u16 keysize; /* out: key size in bits */ u32 attributes; /* out: attribute bits */ }; #define PKEY_VERIFY_ATTR_AES 0x0001 /* key is an AES key */ #define PKEY_VERIFY_ATTR_OLD_MKVP 0x0100 /* key has old MKVP value */ #define PKEY_VERIFYKEY _IOWR(PKEY_IOCTL_MAGIC, 0x07, struct pkey_verifykey) enum pkey_key_type { PKEY_TYPE_CCA_DATA = (u32) 1, PKEY_TYPE_CCA_CIPHER = (u32) 2, PKEY_TYPE_EP11 = (u32) 3, PKEY_TYPE_CCA_ECC = (u32) 0x1f, PKEY_TYPE_EP11_ECC = (u32) 7, }; enum pkey_key_size { PKEY_SIZE_AES_128 = (u32) 128, PKEY_SIZE_AES_192 = (u32) 192, PKEY_SIZE_AES_256 = (u32) 256, PKEY_SIZE_UNKNOWN = (u32) 0xFFFFFFFF, }; #define PKEY_FLAGS_MATCH_CUR_MKVP 0x00000002 #define PKEY_FLAGS_MATCH_ALT_MKVP 0x00000004 #define PKEY_KEYGEN_XPRT_SYM 0x00008000 #define PKEY_KEYGEN_XPRT_UASY 0x00004000 #define PKEY_KEYGEN_XPRT_AASY 0x00002000 #define PKEY_KEYGEN_XPRT_RAW 0x00001000 #define PKEY_KEYGEN_XPRT_CPAC 0x00000800 #define PKEY_KEYGEN_XPRT_DES 0x00000080 #define PKEY_KEYGEN_XPRT_AES 0x00000040 #define PKEY_KEYGEN_XPRT_RSA 0x00000008 struct pkey_apqn { u16 card; u16 domain; }; struct pkey_genseck2 { struct pkey_apqn *apqns; /* in: ptr to list of apqn targets */ u32 apqn_entries; /* in: # of apqn target list entries */ enum pkey_key_type type; /* in: key type to generate */ enum pkey_key_size size; /* in: key size to generate */ u32 keygenflags; /* in: key generation flags */ u8 *key; /* in: pointer to key blob buffer */ u32 keylen; /* in: available key blob buffer size */ /* out: actual key blob size */ }; #define PKEY_GENSECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x11, struct pkey_genseck2) struct pkey_clr2seck2 { struct pkey_apqn *apqns; /* in: ptr to list of apqn targets */ u32 apqn_entries; /* in: # of apqn target list entries */ enum pkey_key_type type; /* in: key type to generate */ enum pkey_key_size size; /* in: key size to generate */ u32 keygenflags; /* in: key generation flags */ struct pkey_clrkey clrkey; /* in: the clear key value */ u8 *key; /* in: pointer to key blob buffer */ u32 keylen; /* in: available key blob buffer size */ /* out: actual key blob size */ }; #define PKEY_CLR2SECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x12, struct pkey_clr2seck2) struct pkey_verifykey2 { u8 *key; /* in: pointer to key blob */ u32 keylen; /* in: key blob size */ u16 cardnr; /* in/out: card number */ u16 domain; /* in/out: domain number */ enum pkey_key_type type; /* out: the key type */ enum pkey_key_size size; /* out: the key size */ u32 flags; /* out: additional key info flags */ }; #define PKEY_VERIFYKEY2 _IOWR(PKEY_IOCTL_MAGIC, 0x17, struct pkey_verifykey2) struct pkey_apqns4key { u8 *key; /* in: pointer to key blob */ u32 keylen; /* in: key blob size */ u32 flags; /* in: match controlling flags */ struct pkey_apqn *apqns; /* in/out: ptr to list of apqn targets*/ u32 apqn_entries; /* in: max # of apqn entries in list */ /* out: # apqns stored into the list */ }; #define PKEY_APQNS4K _IOWR(PKEY_IOCTL_MAGIC, 0x1B, struct pkey_apqns4key) struct pkey_apqns4keytype { enum pkey_key_type type; /* in: key type */ u8 cur_mkvp[32]; /* in: current mkvp */ u8 alt_mkvp[32]; /* in: alternate mkvp */ u32 flags; /* in: match controlling flags */ struct pkey_apqn *apqns; /* in/out: ptr to list of apqn targets*/ u32 apqn_entries; /* in: max # of apqn entries in list */ /* out: # apqns stored into the list */ }; #define PKEY_APQNS4KT _IOWR(PKEY_IOCTL_MAGIC, 0x1C, struct pkey_apqns4keytype) struct pkey_sec2protk { u16 cardnr; /* in: card to use or FFFF for any */ u16 domain; /* in: domain or FFFF for any */ struct pkey_seckey seckey; /* in: the secure key blob */ struct pkey_protkey protkey; /* out: the protected key */ }; #define PKEY_SEC2PROTK _IOWR(PKEY_IOCTL_MAGIC, 0x03, struct pkey_sec2protk) struct pkey_genprotk { u32 keytype; /* in: key type to generate */ struct pkey_protkey protkey; /* out: the protected key */ }; #define PKEY_GENPROTK _IOWR(PKEY_IOCTL_MAGIC, 0x08, struct pkey_genprotk) struct pkey_kblob2pkey2 { 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 */ struct pkey_protkey protkey; /* out: the protected key */ }; #define PKEY_KBLOB2PROTK2 _IOWR(PKEY_IOCTL_MAGIC, 0x1A, struct pkey_kblob2pkey2) /* * EP11 key blobs of type PKEY_TYPE_EP11_AES and PKEY_TYPE_EP11_ECC * are ep11 blobs prepended by this header: */ struct ep11kblob_header { u8 type; /* always 0x00 */ u8 hver; /* header version, currently needs to be 0x00 */ u16 len; /* total length in bytes (including this header) */ u8 version; /* PKEY_TYPE_EP11_AES or PKEY_TYPE_EP11_ECC */ u8 res0; /* unused */ u16 bitlen; /* clear key bit len, 0 for unknown */ u8 res1[8]; /* unused */ } __packed; /* * Transform a key blob into a protected key, version 3. * The difference to version 2 of this ioctl is that the protected key * buffer is now explicitly and not within a struct pkey_protkey any more. * So this ioctl is also able to handle EP11 and CCA ECC secure keys and * provide ECC protected keys. */ 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 KEY_TYPE_CCA_AESDATA "CCA-AESDATA" #define KEY_TYPE_CCA_AESCIPHER "CCA-AESCIPHER" #define KEY_TYPE_EP11_AES "EP11-AES" #define DEFAULT_KEYBITS 256 #define PAES_BLOCK_SIZE 16 #define ENC_ZERO_LEN (2 * PAES_BLOCK_SIZE) #define VERIFICATION_PATTERN_LEN (2 * ENC_ZERO_LEN + 1) #define MKVP_LENGTH 16 static const u8 zero_mkvp[MKVP_LENGTH] = { 0x00 }; #define MKVP_EQ(mkvp1, mkvp2) (memcmp(mkvp1, mkvp2, MKVP_LENGTH) == 0) #define MKVP_ZERO(mkvp) (mkvp == NULL || MKVP_EQ(mkvp, zero_mkvp)) enum card_type { CARD_TYPE_ANY = -1, CARD_TYPE_CCA = 1, CARD_TYPE_EP11 = 2, }; struct ext_lib { struct cca_lib *cca; struct ep11_lib *ep11; }; bool is_cca_aes_data_key(const u8 *key, size_t key_size); bool is_cca_aes_cipher_key(const u8 *key, size_t key_size); bool is_session_bound(const u8 *key, size_t key_size); bool is_ep11_aes_key(const u8 *key, size_t key_size); bool is_ep11_aes_key_with_header(const u8 *key, size_t key_size); bool is_xts_key(const u8 *key, size_t key_size); bool is_cca_ec_key(const u8 *key, size_t key_size); bool is_ep11_ec_key_with_header(const u8 *key, size_t key_size); int alloc_apqns_from_mkvp(int pkeyfd, struct pkey_apqn **apqns, size_t *napqns, const unsigned char mkvp[], int type); #endif libzpc-1.3.0/src/zkey/utils.c000066400000000000000000000061041475140344100160570ustar00rootroot00000000000000/* * zkey - Generate, re-encipher, and validate secure keys * * Copyright IBM Corp. 2019 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include #include #include #include #include #include #include #include #include #include "lib/util_path.h" #include "lib/util_file.h" #include "lib/util_libc.h" #include "lib/util_base.h" #include "utils.h" #include "debug.h" #define pr_verbose(verbose, fmt...) do { \ if (verbose) \ DEBUG(fmt); \ } while (0) /** * Checks if the specified card is of the specified type and is online * * @param[in] card card number * @param[in] cardtype card type (CCA, EP11 or ANY) * * @returns 1 if its card of the specified type and is online, * 0 if offline, * -1 if its not the specified type. */ int sysfs_is_card_online(unsigned int card, enum card_type cardtype) { long int online; char *dev_path; char type[20]; int rc = 1; dev_path = util_path_sysfs("bus/ap/devices/card%02x", card); if (!util_path_is_dir(dev_path)) { rc = 0; goto out; } if (util_file_read_l(&online, 10, "%s/online", dev_path) != 0) { rc = 0; goto out; } if (online == 0) { rc = 0; goto out; } if (util_file_read_line(type, sizeof(type), "%s/type", dev_path) != 0) { rc = 0; goto out; } if (strncmp(type, "CEX", 3) != 0 || strlen(type) < 5) { rc = 0; goto out; } switch (cardtype) { case CARD_TYPE_CCA: if (type[4] != 'C') { rc = -1; goto out; } break; case CARD_TYPE_EP11: if (type[4] != 'P') { rc = -1; goto out; } break; default: break; } out: free(dev_path); return rc; } /** * Gets the 8-16 character ASCII serial number string of an card from the sysfs. * * @param[in] card card number * @param[out] serialnr Result buffer. Must be at least SERIALNR_LENGTH long. * @param[in] verbose if true, verbose messages are printed * * @returns 0 if the serial number was returned. -ENODEV if the APQN is not * available, or is not a CCA or EP11 card. * -ENOTSUP if the serialnr sysfs attribute is not available, because * the zcrypt kernel module is on an older level. */ int sysfs_get_serialnr(unsigned int card, char *serialnr, bool verbose) { char *dev_path; int rc = 0; if (serialnr == NULL) return -EINVAL; if (sysfs_is_card_online(card, CARD_TYPE_ANY) != 1) return -ENODEV; dev_path = util_path_sysfs("bus/ap/devices/card%02x", card); if (!util_path_is_dir(dev_path)) { rc = -ENODEV; goto out; } if (util_file_read_line(serialnr, SERIALNR_LENGTH, "%s/serialnr", dev_path) != 0) { rc = -ENOTSUP; goto out; } if (strlen(serialnr) == 0) { rc = -ENODEV; goto out; } pr_verbose(verbose, "Serial number of %02x: %s", card, serialnr); out: if (rc != 0) pr_verbose(verbose, "Failed to get serial number for " "%02x: %s", card, strerror(-rc)); free(dev_path); return rc; } libzpc-1.3.0/src/zkey/utils.h000066400000000000000000000010701475140344100160610ustar00rootroot00000000000000/* * zkey - Generate, re-encipher, and validate secure keys * * This header file defines the interface to the CCA host library. * * Copyright IBM Corp. 2019 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef UTILS_H #define UTILS_H #include "lib/zt_common.h" #include "pkey.h" int sysfs_is_card_online(unsigned int card, enum card_type cardtype); #define SERIALNR_LENGTH 17 int sysfs_get_serialnr(unsigned int card, char *serialnr, bool verbose); #endif libzpc-1.3.0/test/000077500000000000000000000000001475140344100137605ustar00rootroot00000000000000libzpc-1.3.0/test/TEST.md000066400000000000000000000002711475140344100150610ustar00rootroot00000000000000test === testlib --- Functions used by multiple test suites. b_*test* --- Simple build tests. t_*testsuite* --- Test suites using the googletest framework. Part of the test program. libzpc-1.3.0/test/b_aes_cbc.c000066400000000000000000000004341475140344100160050ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ /* * Build test for aes_cbc.h. */ #include "zpc/aes_cbc.h" #include "zpc/aes_cbc.h" int b_aes_cbc_not_empty; libzpc-1.3.0/test/b_aes_ccm.c000066400000000000000000000004341475140344100160200ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ /* * Build test for aes_ccm.h. */ #include "zpc/aes_ccm.h" #include "zpc/aes_ccm.h" int b_aes_ccm_not_empty; libzpc-1.3.0/test/b_aes_cmac.c000066400000000000000000000004401475140344100161560ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ /* * Build test for aes_cmac.h. */ #include "zpc/aes_cmac.h" #include "zpc/aes_cmac.h" int b_aes_cmac_not_empty; libzpc-1.3.0/test/b_aes_ecb.c000066400000000000000000000004341475140344100160070ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ /* * Build test for aes_ecb.h. */ #include "zpc/aes_ecb.h" #include "zpc/aes_ecb.h" int b_aes_ecb_not_empty; libzpc-1.3.0/test/b_aes_gcm.c000066400000000000000000000004341475140344100160240ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ /* * Build test for aes_gcm.h. */ #include "zpc/aes_gcm.h" #include "zpc/aes_gcm.h" int b_aes_gcm_not_empty; libzpc-1.3.0/test/b_aes_key.c000066400000000000000000000004341475140344100160460ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ /* * Build test for aes_key.h. */ #include "zpc/aes_key.h" #include "zpc/aes_key.h" int b_aes_key_not_empty; libzpc-1.3.0/test/b_aes_xts.c000066400000000000000000000004341475140344100160740ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ /* * Build test for aes_xts.h. */ #include "zpc/aes_xts.h" #include "zpc/aes_xts.h" int b_aes_xts_not_empty; libzpc-1.3.0/test/b_ecc_key.c000066400000000000000000000004341475140344100160300ustar00rootroot00000000000000/* * Copyright IBM Corp. 2022 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ /* * Build test for ecc_key.h. */ #include "zpc/ecc_key.h" #include "zpc/ecc_key.h" int b_ecc_key_not_empty; libzpc-1.3.0/test/b_ecdsa_ctx.c000066400000000000000000000004441475140344100163640ustar00rootroot00000000000000/* * Copyright IBM Corp. 2022 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ /* * Build test for ecdsa_ctx.h. */ #include "zpc/ecdsa_ctx.h" #include "zpc/ecdsa_ctx.h" int b_ecdsa_ctx_not_empty; libzpc-1.3.0/test/b_error.c000066400000000000000000000004241475140344100155560ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ /* * Build test for error.h. */ #include "zpc/error.h" #include "zpc/error.h" int b_error_not_empty; libzpc-1.3.0/test/b_headers.c000066400000000000000000000021621475140344100160410ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ /* * Build test for public header files. */ #include "zpc/error.h" #include "zpc/aes_key.h" #include "zpc/aes_gcm.h" #include "zpc/aes_ccm.h" #include "zpc/aes_xts.h" #include "zpc/aes_cbc.h" #include "zpc/aes_ecb.h" #include "zpc/aes_cmac.h" #include "zpc/ecc_key.h" #include "zpc/ecdsa_ctx.h" #ifndef ZPC_ERROR_H # error "ZPC_ERROR_H undefined." #endif #ifndef ZPC_AES_KEY_H # error "ZPC_AES_KEY_H undefined." #endif #ifndef ZPC_AES_GCM_H # error "ZPC_AES_GCM_H undefined." #endif #ifndef ZPC_AES_CCM_H # error "ZPC_AES_CCM_H undefined." #endif #ifndef ZPC_AES_XTS_H # error "ZPC_AES_XTS_H undefined." #endif #ifndef ZPC_AES_CBC_H # error "ZPC_AES_CBC_H undefined." #endif #ifndef ZPC_AES_ECB_H # error "ZPC_AES_ECB_H undefined." #endif #ifndef ZPC_AES_CMAC_H # error "ZPC_AES_CMC_H undefined." #endif #ifndef ZPC_ECDSA_CTX_H # error "ZPC_ECDSA_CTX_H undefined." #endif #ifndef ZPC_ECC_KEY_H # error "ZPC_ECC_KEY_H undefined." #endif int b_headers_not_empty; libzpc-1.3.0/test/b_platform.c000066400000000000000000000004511475140344100162510ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #if !defined(__linux__) && !defined(__s390x__) # error "Supported platforms: linux-s390x." #endif int b_platform_not_empty; libzpc-1.3.0/test/t_aes_cbc.cc000066400000000000000000001340251475140344100161760ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "testlib.h" #include "gtest/gtest.h" #include "zpc/aes_cbc.h" #include "zpc/error.h" #include "aes_key_local.h" /* de-opaquify struct zpc_aes_key */ #include "aes_cbc_local.h" /* de-opaquify struct zpc_aes_cbc */ #include #include #include #include static void __run_json(const char *json); TEST(aes_cbc, alloc) { struct zpc_aes_cbc *aes_cbc; int rc; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); rc = zpc_aes_cbc_alloc(NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); aes_cbc = NULL; rc = zpc_aes_cbc_alloc(&aes_cbc); EXPECT_EQ(rc, 0); zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); aes_cbc = (struct zpc_aes_cbc *)&aes_cbc; rc = zpc_aes_cbc_alloc(&aes_cbc); EXPECT_EQ(rc, 0); zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); } TEST(aes_cbc, free) { struct zpc_aes_cbc *aes_cbc; int rc; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); zpc_aes_cbc_free(NULL); aes_cbc = NULL; zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); rc = zpc_aes_cbc_alloc(&aes_cbc); EXPECT_EQ(rc, 0); zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); } TEST(aes_cbc, set_key) { struct zpc_aes_key *aes_key; struct zpc_aes_cbc *aes_cbc; u8 clearkey[32], iv[16]; unsigned int flags = 0; const char *mkvp, *apqns[257]; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, clearkey); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_cbc_set_key(NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_cbc_set_key(NULL, aes_key); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_cbc_set_key(aes_cbc, NULL); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); ret: zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_cbc, set_iv) { struct zpc_aes_key *aes_key; struct zpc_aes_cbc *aes_cbc; const char *mkvp, *apqns[257]; u8 iv[16]; int rc, size, type; unsigned int flags; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_cbc_set_iv(NULL, iv); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_cbc_set_iv(aes_cbc, NULL); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); ret: zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_cbc, encrypt) { struct zpc_aes_key *aes_key; struct zpc_aes_cbc *aes_cbc; const char *mkvp, *apqns[257]; u8 iv[16], m[64], c[64]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc, c, m, 64); EXPECT_EQ(rc, 0); ret: zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_cbc, decrypt) { struct zpc_aes_key *aes_key; struct zpc_aes_cbc *aes_cbc; const char *mkvp, *apqns[257]; u8 iv[16], m[64], c[64]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc, m, c, 64); EXPECT_EQ(rc, 0); ret: zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_cbc, pc) { struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_cbc *aes_cbc1, *aes_cbc2; const char *mkvp, *apqns[257]; u8 iv[16], m[96], c[96], key[32], m_bak[96]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); memcpy(m_bak, m, 96); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc1); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key1, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_cbc_set_key(aes_cbc1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc1, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key2, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key2, size); if (rc) goto ret; } rc = zpc_aes_cbc_set_key(aes_cbc2, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc2, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc1, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc2, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); rc = zpc_aes_cbc_encrypt(aes_cbc2, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc1, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); rc = zpc_aes_cbc_encrypt(aes_cbc2, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc1, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); rc = zpc_aes_cbc_encrypt(aes_cbc1, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc2, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); /* Random protected key */ rc = zpc_aes_cbc_set_key(aes_cbc1, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_key(aes_cbc2, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(aes_key1, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_cbc_set_key(aes_cbc1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc1, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_key(aes_cbc2, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc2, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc1, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc2, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); rc = zpc_aes_cbc_encrypt(aes_cbc2, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc1, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); rc = zpc_aes_cbc_encrypt(aes_cbc2, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc1, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); rc = zpc_aes_cbc_encrypt(aes_cbc1, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc2, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); ret: zpc_aes_cbc_free(&aes_cbc2); zpc_aes_cbc_free(&aes_cbc1); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); } TEST(aes_cbc, stream_inplace_kat1) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); size_t keylen, msglen, ctlen, ivlen; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_cbc *aes_cbc; unsigned int flags; int type, rc; const char *keystr = "b6f9afbfe5a1562bba1368fc72ac9d9c"; const char *ivstr = "3f9d5ebe250ee7ce384b0d00ee849322"; const char *msgstr = "db397ec22718dbffb9c9d13de0efcd4611bf792be4fce0dc5f25d4f577ed8cdbd4eb9208d593dda3d4653954ab64f05676caa3ce9bfa795b08b67ceebc923fdc89a8c431188e9e482d8553982cf304d1"; const char *ctstr = "10ea27b19e16b93af169c4a88e06e35c99d8b420980b058e34b4b8f132b13766f72728202b089f428fecdb41c79f8aa0d0ef68f5786481cca29e2126f69bc14160f1ae2187878ba5c49cf3961e1b7ee9"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping stream_inplace_kat1 test. KATs cannot be performed with UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(iv); free(msg); free(ct); } TEST(aes_cbc, stream_inplace_kat2) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); size_t keylen, ivlen, msglen, ctlen; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_cbc *aes_cbc; unsigned int flags; int type, rc; const char *keystr = "b6f9afbfe5a1562bba1368fc72ac9d9c"; const char *ivstr = "3f9d5ebe250ee7ce384b0d00ee849322"; const char *msgstr = "db397ec22718dbffb9c9d13de0efcd4611bf792be4fce0dc5f25d4f577ed8cdbd4eb9208d593dda3d4653954ab64f05676caa3ce9bfa795b08b67ceebc923fdc89a8c431188e9e482d8553982cf304d1"; const char *ctstr = "10ea27b19e16b93af169c4a88e06e35c99d8b420980b058e34b4b8f132b13766f72728202b089f428fecdb41c79f8aa0d0ef68f5786481cca29e2126f69bc14160f1ae2187878ba5c49cf3961e1b7ee9"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping stream_inplace_kat2 test. KATs cannot be performed with UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc, buf, buf, msglen); /* Works iff msglen == 0 mod 16 */ EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc, buf, buf, msglen); /* Works iff msglen == 0 mod 16 */ EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(iv); free(msg); free(ct); } TEST(aes_cbc, stream_inplace_kat3) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); size_t keylen, ivlen, msglen, ctlen; unsigned char buf[4096], iv2[16]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_cbc *aes_cbc1, *aes_cbc2; unsigned int flags; int type, rc; const char *keystr = "b6f9afbfe5a1562bba1368fc72ac9d9c"; const char *ivstr = "3f9d5ebe250ee7ce384b0d00ee849322"; const char *msgstr = "db397ec22718dbffb9c9d13de0efcd4611bf792be4fce0dc5f25d4f577ed8cdbd4eb9208d593dda3d4653954ab64f05676caa3ce9bfa795b08b67ceebc923fdc89a8c431188e9e482d8553982cf304d1"; const char *ctstr = "10ea27b19e16b93af169c4a88e06e35c99d8b420980b058e34b4b8f132b13766f72728202b089f428fecdb41c79f8aa0d0ef68f5786481cca29e2126f69bc14160f1ae2187878ba5c49cf3961e1b7ee9"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping stream_inplace_kat3 test. KATs cannot be performed with UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc1); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_key(aes_cbc1, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_key(aes_cbc2, aes_key); EXPECT_EQ(rc, 0); /* Encrypt first chunk with first ctx */ memcpy(buf, msg, msglen); rc = zpc_aes_cbc_set_iv(aes_cbc1, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc1, buf, buf, 16); EXPECT_EQ(rc, 0); /* Get intermediate iv from first ctx */ rc = zpc_aes_cbc_get_intermediate_iv(aes_cbc1, iv2); EXPECT_EQ(rc, 0); /* Encrypt a 2nd chunk with 2nd ctx */ rc = zpc_aes_cbc_set_iv(aes_cbc2, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_intermediate_iv(aes_cbc2, iv2); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc2, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Decrypt first chunk with first ctx */ memcpy(buf, ct, ctlen); rc = zpc_aes_cbc_set_iv(aes_cbc1, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc1, buf, buf, 16); EXPECT_EQ(rc, 0); /* Get intermediate iv from first ctx */ rc = zpc_aes_cbc_get_intermediate_iv(aes_cbc1, iv2); EXPECT_EQ(rc, 0); /* Decrypt remaining chunk with 2nd ctx */ rc = zpc_aes_cbc_set_iv(aes_cbc2, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_intermediate_iv(aes_cbc2, iv2); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc2, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_cbc_free(&aes_cbc1); EXPECT_EQ(aes_cbc1, nullptr); zpc_aes_cbc_free(&aes_cbc2); EXPECT_EQ(aes_cbc2, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(iv); free(msg); free(ct); } TEST(aes_cbc, nist_kat) { int type; type = testlib_env_aes_key_type(); TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping nist_kat test. KATs cannot be performed with UV secrets."); __run_json("nist_aes_cbc.json"); } static void __run_json(const char *json) { const char *tv = json, *str; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_cbc *aes_cbc; unsigned int flags; u8 *key = NULL, *iv = NULL; u8 *pt = NULL, *pt_out = NULL, *ct = NULL, *ct_out = NULL; int rc, keysize = 0; size_t ptlen, ctlen, i, j, max; json_object *jkey, *jiv, *jmsg, *jct, *jtmp, *jtestgroups, *jfile, *jkeysize, *jtests; json_bool b; int type; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); jfile = json_object_from_file(tv); ASSERT_NE(jfile, nullptr); b = json_object_object_get_ex(jfile, "testGroups", &jtestgroups); ASSERT_TRUE(b); for (i = 0; i < (size_t)json_object_array_length(jtestgroups); i++) { jtmp = json_object_array_get_idx(jtestgroups, i); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "keySize", &jkeysize); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "tests", &jtests); ASSERT_TRUE(b); keysize = json_object_get_int(jkeysize); rc = zpc_aes_key_set_size(aes_key, keysize); EXPECT_EQ(rc, 0); for (j = 0; j < (size_t)json_object_array_length(jtests); j++) { jtmp = json_object_array_get_idx(jtests, j); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "key", &jkey); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "iv", &jiv); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "msg", &jmsg); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "ct", &jct); ASSERT_TRUE(b); str = json_object_get_string(jkey); ASSERT_NE(str, nullptr); key = testlib_hexstr2buf(str, NULL); ASSERT_NE(key, nullptr); str = json_object_get_string(jiv); ASSERT_NE(str, nullptr); iv = testlib_hexstr2buf(str, NULL); str = json_object_get_string(jmsg); ASSERT_NE(str, nullptr); pt = testlib_hexstr2buf(str, &ptlen); str = json_object_get_string(jct); ASSERT_NE(str, nullptr); ct = testlib_hexstr2buf(str, &ctlen); max = ptlen > ctlen ? ptlen : ctlen; pt_out = NULL; ct_out = NULL; if (max > 0) { pt_out = (unsigned char *)calloc(1, max); ASSERT_NE(pt_out, nullptr); ct_out = (unsigned char *)calloc(1, max); ASSERT_NE(ct_out, nullptr); } rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc, ct_out, pt, ptlen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(ct_out, ct, ctlen) == 0); rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc, pt_out, ct, ctlen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(pt_out, pt, ptlen) == 0); /* Unset key. */ rc = zpc_aes_cbc_set_key(aes_cbc, NULL); EXPECT_EQ(rc, 0); free(key); key = NULL; free(iv); iv = NULL; free(pt); pt = NULL; free(pt_out); pt_out = NULL; free(ct); ct = NULL; free(ct_out); ct_out = NULL; } } zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_cbc, rederive_protected_key1) { struct zpc_aes_key *aes_key1; struct zpc_aes_cbc *aes_cbc1, *aes_cbc2, *aes_cbc3; u8 iv[16], m[96], c[96]; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); TESTLIB_AES_KERNEL_CAPS_CHECK(type); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc1); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc2); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc3); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_key(aes_cbc1, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_key(aes_cbc2, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_key(aes_cbc3, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); /* Random protected keys cannot be re-derived. */ rc = zpc_aes_key_set_mkvp(aes_key1, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); /* * This key obj has no type set. Therefore the generate will work also * for tests with ZPC_TEST_AES_KEY_TYPE = ZPC_AES_KEY_TYPE_PVSECRET. * The generated protected key has no dependency on any secure key or * pvsecret. */ rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_key(aes_cbc1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc1, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_key(aes_cbc2, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc2, iv); EXPECT_EQ(rc, 0); memset(aes_cbc2->param.protkey, 0, sizeof(aes_cbc2->param.protkey)); rc = zpc_aes_cbc_encrypt(aes_cbc2, c, m, 96); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); rc = zpc_aes_cbc_set_key(aes_cbc3, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(aes_cbc3, iv); EXPECT_EQ(rc, 0); memset(aes_cbc3->param.protkey, 0, sizeof(aes_cbc3->param.protkey)); rc = zpc_aes_cbc_decrypt(aes_cbc3, m, c, 96); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); zpc_aes_cbc_free(&aes_cbc3); zpc_aes_cbc_free(&aes_cbc2); zpc_aes_cbc_free(&aes_cbc1); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_cbc3, nullptr); EXPECT_EQ(aes_cbc2, nullptr); EXPECT_EQ(aes_cbc1, nullptr); EXPECT_EQ(aes_key1, nullptr); } TEST(aes_cbc, rederive_protected_key2) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); size_t keylen, msglen, ctlen, ivlen; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_cbc *aes_cbc; unsigned int flags; int type, rc; const char *keystr = "b6f9afbfe5a1562bba1368fc72ac9d9c"; const char *ivstr = "3f9d5ebe250ee7ce384b0d00ee849322"; const char *msgstr = "db397ec22718dbffb9c9d13de0efcd4611bf792be4fce0dc5f25d4f577ed8cdbd4eb9208d593dda3d4653954ab64f05676caa3ce9bfa795b08b67ceebc923fdc89a8c431188e9e482d8553982cf304d1"; const char *ctstr = "10ea27b19e16b93af169c4a88e06e35c99d8b420980b058e34b4b8f132b13766f72728202b089f428fecdb41c79f8aa0d0ef68f5786481cca29e2126f69bc14160f1ae2187878ba5c49cf3961e1b7ee9"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 128, flags); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, keylen * 8); if (rc) goto ret; } /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, 0); memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_encrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); } /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, 0); memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_encrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_encrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); } /* Decrypt */ memcpy(buf, ct, ctlen); memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_decrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); } /* Decrypt */ memcpy(buf, ct, ctlen); memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_decrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); } ret: zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(iv); free(msg); free(ct); } TEST(aes_cbc, reencipher) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); size_t keylen, msglen, ctlen, ivlen; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_cbc *aes_cbc; unsigned int flags; int type, rc; const char *keystr = "b6f9afbfe5a1562bba1368fc72ac9d9c"; const char *ivstr = "3f9d5ebe250ee7ce384b0d00ee849322"; const char *msgstr = "db397ec22718dbffb9c9d13de0efcd4611bf792be4fce0dc5f25d4f577ed8cdbd4eb9208d593dda3d4653954ab64f05676caa3ce9bfa795b08b67ceebc923fdc89a8c431188e9e482d8553982cf304d1"; const char *ctstr = "10ea27b19e16b93af169c4a88e06e35c99d8b420980b058e34b4b8f132b13766f72728202b089f428fecdb41c79f8aa0d0ef68f5786481cca29e2126f69bc14160f1ae2187878ba5c49cf3961e1b7ee9"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 128, flags); TESTLIB_AES_NEW_MK_CHECK(type, mkvp, apqns); if (type == ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping reencipher test. Not applicable for UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&aes_cbc); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_reencipher(aes_key, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key->cur, 0, sizeof(aes_key->cur)); /* destroy current secure key */ /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_encrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_encrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_encrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_decrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_decrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(iv); free(msg); free(ct); } /* * This test assumes that the tester manually added the clear AES key with * given size to the pvsecret list file, for example: * * 5 AES-128-KEY: * 0x8ace2a9bc6f28ae3 ... <- secret ID * 0xbe0274e3f3b36 ... <- clear AES key * ... * * The test creates one pvsecret-type key and one CCA or EP11 type * single AES key with the given clear key material to compare results. * The specified APQN(s) decide if the single keys are CCA or EP11. */ TEST(aes_cbc, pvsecret_kat) { struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_cbc *ctx1, *ctx2; u8 iv[16], m[96], c[96], m_bak[96], c_bak[96]; const char *mkvp, *apqns[257]; unsigned int flags; int type, type2, rc, size; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); if (type != ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping pvsecret_kat test. Only applicable for UV secrets."); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); TESTLIB_EC_NEW_MK_CHECK(type, mkvp, apqns); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&ctx1); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_alloc(&ctx2); EXPECT_EQ(rc, 0); /* * key1 is created from pvsecret. */ rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; rc = zpc_aes_cbc_set_key(ctx1, aes_key1); EXPECT_EQ(rc, 0); /* * key2 is a normal AES key and contains clear key material from list * file. We first try to create a CCA type key with the given APQN(s), * if this fails we retry with EP11. */ type2 = ZPC_AES_KEY_TYPE_CCA_DATA; while (1) { rc = zpc_aes_key_set_type(aes_key2, type2); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = testlib_set_aes_key_from_file(aes_key2, type2, size); if (rc == ZPC_ERROR_IOCTLCLR2SECK2) { type2 = ZPC_AES_KEY_TYPE_EP11; continue; } if (rc) goto ret; else break; } rc = zpc_aes_cbc_set_key(ctx2, aes_key2); EXPECT_EQ(rc, 0); memcpy(m_bak, m, 96); /* Now encrypt with both keys and compare result */ rc = zpc_aes_cbc_set_iv(ctx1, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(ctx1, c, m, 96); EXPECT_EQ(rc, 0); memcpy(c_bak, c, 96); rc = zpc_aes_cbc_set_iv(ctx2, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(ctx2, c, m, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(c, c_bak, 96) == 0); /* Now encrypt with key1 and decrypt with key2 */ rc = zpc_aes_cbc_set_iv(ctx1, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(ctx1, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_iv(ctx2, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(ctx2, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); ret: zpc_aes_cbc_free(&ctx1); EXPECT_EQ(ctx1, nullptr); zpc_aes_cbc_free(&ctx2); EXPECT_EQ(ctx2, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); } static void __task(struct zpc_aes_key *aes_key) { struct zpc_aes_cbc *aes_cbc; unsigned char buf[4096]; size_t ivlen, msglen, ctlen; int rc, i; const char *ivstr = "3f9d5ebe250ee7ce384b0d00ee849322"; const char *msgstr = "db397ec22718dbffb9c9d13de0efcd4611bf792be4fce0dc5f25d4f577ed8cdbd4eb9208d593dda3d4653954ab64f05676caa3ce9bfa795b08b67ceebc923fdc89a8c431188e9e482d8553982cf304d1"; const char *ctstr = "10ea27b19e16b93af169c4a88e06e35c99d8b420980b058e34b4b8f132b13766f72728202b089f428fecdb41c79f8aa0d0ef68f5786481cca29e2126f69bc14160f1ae2187878ba5c49cf3961e1b7ee9"; u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_cbc_alloc(&aes_cbc); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_set_key(aes_cbc, aes_key); EXPECT_EQ(rc, 0); for (i = 0; i < 1000; i++) { /* Encrypt */ memcpy(buf, msg, msglen); memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_encrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_encrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); if (aes_key->type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); } /* Decrypt */ if (aes_key->type != ZPC_AES_KEY_TYPE_PVSECRET) { memcpy(buf, ct, ctlen); } rc = zpc_aes_cbc_set_iv(aes_cbc, iv); EXPECT_EQ(rc, 0); memset(aes_cbc->param.protkey, 0, sizeof(aes_cbc->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cbc_decrypt(aes_cbc, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cbc_decrypt(aes_cbc, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); } zpc_aes_cbc_free(&aes_cbc); EXPECT_EQ(aes_cbc, nullptr); free(iv); free(msg); free(ct); } TEST(aes_cbc, threads) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CBC_HW_CAPS_CHECK(); size_t keylen; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; unsigned int flags; int type, rc, i; std::thread *t[500]; const char *keystr = "b6f9afbfe5a1562bba1368fc72ac9d9c"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 128, flags); TESTLIB_AES_NEW_MK_CHECK(type, mkvp, apqns); u8 *key = testlib_hexstr2buf(keystr, &keylen); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, keylen * 8); if (rc) goto ret; } for (i = 0; i < 500; i++) { t[i] = new std::thread(__task, aes_key); } /* Do something with key object while threads are working with it. */ if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_reencipher(aes_key, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key->cur, 0, sizeof(aes_key->cur)); /* destroy current secure key */ } for (i = 0; i < 500; i++) { memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ usleep(1); } for (i = 0; i < 500; i++) { t[i]->join(); delete t[i]; } ret: zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); } libzpc-1.3.0/test/t_aes_ccm.cc000066400000000000000000001270121475140344100162070ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "testlib.h" #include "gtest/gtest.h" #include "zpc/aes_ccm.h" #include "zpc/error.h" #include "aes_key_local.h" /* de-opaquify struct zpc_aes_key */ #include "aes_ccm_local.h" /* de-opaquify struct zpc_aes_ccm */ #include #include #include #include static void __run_json(const char *json); TEST(aes_ccm, alloc) { struct zpc_aes_ccm *aes_ccm; int rc; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); rc = zpc_aes_ccm_alloc(NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); aes_ccm = NULL; rc = zpc_aes_ccm_alloc(&aes_ccm); EXPECT_EQ(rc, 0); zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); aes_ccm = (struct zpc_aes_ccm *)&aes_ccm; rc = zpc_aes_ccm_alloc(&aes_ccm); EXPECT_EQ(rc, 0); zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); } TEST(aes_ccm, free) { struct zpc_aes_ccm *aes_ccm; int rc; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); zpc_aes_ccm_free(NULL); aes_ccm = NULL; zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); rc = zpc_aes_ccm_alloc(&aes_ccm); EXPECT_EQ(rc, 0); zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); } TEST(aes_ccm, set_key) { struct zpc_aes_key *aes_key; struct zpc_aes_ccm *aes_ccm; u8 clearkey[32], iv[12]; unsigned int flags = 0; const char *mkvp, *apqns[257]; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, clearkey); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_ccm_set_key(NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_ccm_set_key(NULL, aes_key); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_ccm_set_key(aes_ccm, NULL); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, 12); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, 12); EXPECT_EQ(rc, 0); ret: zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_ccm, set_iv) { struct zpc_aes_key *aes_key; struct zpc_aes_ccm *aes_ccm; const char *mkvp, *apqns[257]; u8 iv[16]; int rc, size, type; unsigned int flags; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(NULL, NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_ccm_set_iv(NULL, iv, 12); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_ccm_set_iv(aes_ccm, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, 12); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_ccm_set_iv(aes_ccm, iv, 12); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, 0); EXPECT_EQ(rc, ZPC_ERROR_IVSIZE); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, SIZE_MAX); EXPECT_EQ(rc, ZPC_ERROR_IVSIZE); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, 13); EXPECT_EQ(rc, 0); ret: zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_ccm, encrypt) { struct zpc_aes_key *aes_key; struct zpc_aes_ccm *aes_ccm; const char *mkvp, *apqns[257]; u8 iv[12], aad[99], m[99], tag[12], c[99]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_encrypt(aes_ccm, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); ret: zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_ccm, decrypt) { struct zpc_aes_key *aes_key; struct zpc_aes_ccm *aes_ccm; const char *mkvp, *apqns[257]; u8 iv[12], aad[99], m[99], tag[12] = { 0,}, c[99]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_decrypt(aes_ccm, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); ret: zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_ccm, pc) { struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_ccm *aes_ccm1, *aes_ccm2; const char *mkvp, *apqns[257]; u8 iv[12], aad[99], m[99], tag[12], c[99], key[32], m_bak[99]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); memcpy(m_bak, m, 99); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm1); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key1, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_ccm_set_key(aes_ccm1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm1, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key2, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key2, size); if (rc) goto ret; } rc = zpc_aes_ccm_set_key(aes_ccm2, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm2, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_encrypt(aes_ccm1, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_decrypt(aes_ccm2, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 99) == 0); rc = zpc_aes_ccm_encrypt(aes_ccm2, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_decrypt(aes_ccm1, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 99) == 0); rc = zpc_aes_ccm_encrypt(aes_ccm2, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); c[0] ^= 1; rc = zpc_aes_ccm_decrypt(aes_ccm1, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); rc = zpc_aes_ccm_encrypt(aes_ccm1, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); tag[0] ^= 1; rc = zpc_aes_ccm_decrypt(aes_ccm2, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); memcpy(m_bak, m, 99); /* Random protected key */ rc = zpc_aes_ccm_set_key(aes_ccm1, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_key(aes_ccm2, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(aes_key1, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_ccm_set_key(aes_ccm1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm1, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_key(aes_ccm2, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm2, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_encrypt(aes_ccm1, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_decrypt(aes_ccm2, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 99) == 0); rc = zpc_aes_ccm_encrypt(aes_ccm2, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_decrypt(aes_ccm1, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 99) == 0); rc = zpc_aes_ccm_encrypt(aes_ccm2, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); c[0] ^= 1; rc = zpc_aes_ccm_decrypt(aes_ccm1, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); rc = zpc_aes_ccm_encrypt(aes_ccm1, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); tag[0] ^= 1; rc = zpc_aes_ccm_decrypt(aes_ccm2, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); ret: zpc_aes_ccm_free(&aes_ccm2); zpc_aes_ccm_free(&aes_ccm1); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); } TEST(aes_ccm, stream_inplace_kat1) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); size_t keylen, ivlen, msglen, ctlen, taglen, aadlen; unsigned char buf[4096], mac[16]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_ccm *aes_ccm; unsigned int flags; int type, rc; const char *keystr = "e258b117c2fdd75587f07b400ae4af3e673a51dcf761e4ca"; const char *ivstr = "5ead03aa8c720d21b77075db"; const char *aadstr = "27702950960b9c79"; const char *msgstr = "afe96113a684bc52a6d962cf2724f6791d"; const char *ctstr = "7830446f333057d996a1a79b21c68d8b43"; const char *tagstr = "72ac478a66f5637563f1f12c1d0267ca"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping stream_inplace_kat1 test. KATs cannot be performed with UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *aad = testlib_hexstr2buf(aadstr, &aadlen); ASSERT_NE(aad, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_encrypt(aes_ccm, buf, mac, taglen, aad, aadlen, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_encrypt(aes_ccm, buf, mac, taglen, aad, aadlen, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_decrypt(aes_ccm, buf, tag, taglen, aad, aadlen, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_decrypt(aes_ccm, buf, tag, taglen, aad, aadlen, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(iv); free(aad); free(msg); free(ct); free(tag); } TEST(aes_ccm, stream_inplace_kat2) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); size_t keylen, ivlen, msglen, ctlen, taglen, aadlen; unsigned char buf[4096], mac[16]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_ccm *aes_ccm; unsigned int flags; int type, rc; const char *keystr = "e258b117c2fdd75587f07b400ae4af3e673a51dcf761e4ca"; const char *ivstr = "5ead03aa8c720d21b77075db"; const char *aadstr = "27702950960b9c79"; const char *msgstr = "afe96113a684bc52a6d962cf2724f6791d"; const char *ctstr = "7830446f333057d996a1a79b21c68d8b43"; const char *tagstr = "72ac478a66f5637563f1f12c1d0267ca"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping stream_inplace_kat2 test. KATs cannot be performed with UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *aad = testlib_hexstr2buf(aadstr, &aadlen); ASSERT_NE(aad, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_encrypt(aes_ccm, buf, mac, taglen, aad, aadlen, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_decrypt(aes_ccm, buf, tag, taglen, aad, aadlen, buf, msglen); /* Works iff msglen == 0 mod 16 */ EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(iv); free(aad); free(msg); free(ct); free(tag); } TEST(aes_ccm, wycheproof_kat) { int type; type = testlib_env_aes_key_type(); TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping wycheproof_kat test. KATs cannot be performed with UV secrets."); __run_json("wycheproof/src/wycheproof/testvectors/aes_ccm_test.json"); } static void __run_json(const char *json) { const char *tv = json, *str; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_ccm *aes_ccm; unsigned int flags; u8 *key = NULL, *iv = NULL, *aad = NULL; u8 *pt = NULL, *pt_out = NULL, *ct = NULL, *ct_out = NULL; u8 *tag = NULL, *tag_out = NULL; int rc, tagsize = 0, ivsize = 0, keysize = 0; int valid = 0, ivlen0 = 0, tag0 = 0, nonce0 = 0; size_t aadlen, ptlen, ctlen, taglen, i, j, k, max; json_object *jkey, *jiv, *jtag, *jaad, *jmsg, *jct, *jresult, *jflags, *jtmp, *jtestgroups, *jfile, *jkeysize, *jivsize, *jtagsize, *jtests; json_bool b; int type; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); jfile = json_object_from_file(tv); ASSERT_NE(jfile, nullptr); b = json_object_object_get_ex(jfile, "testGroups", &jtestgroups); ASSERT_TRUE(b); for (i = 0; i < (size_t)json_object_array_length(jtestgroups); i++) { jtmp = json_object_array_get_idx(jtestgroups, i); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "keySize", &jkeysize); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "ivSize", &jivsize); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "tagSize", &jtagsize); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "tests", &jtests); ASSERT_TRUE(b); keysize = json_object_get_int(jkeysize); ivsize = json_object_get_int(jivsize); tagsize = json_object_get_int(jtagsize); rc = zpc_aes_key_set_size(aes_key, keysize); EXPECT_EQ(rc, 0); for (j = 0; j < (size_t)json_object_array_length(jtests); j++) { jtmp = json_object_array_get_idx(jtests, j); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "key", &jkey); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "iv", &jiv); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "tag", &jtag); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "aad", &jaad); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "msg", &jmsg); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "ct", &jct); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "flags", &jflags); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "result", &jresult); ASSERT_TRUE(b); str = json_object_get_string(jkey); ASSERT_NE(str, nullptr); key = testlib_hexstr2buf(str, NULL); ASSERT_NE(key, nullptr); str = json_object_get_string(jiv); ASSERT_NE(str, nullptr); iv = testlib_hexstr2buf(str, NULL); str = json_object_get_string(jtag); ASSERT_NE(str, nullptr); tag = testlib_hexstr2buf(str, &taglen); ASSERT_NE(tag, nullptr); tag_out = (unsigned char *)calloc(1, taglen); ASSERT_NE(tag_out, nullptr); str = json_object_get_string(jaad); ASSERT_NE(str, nullptr); aad = testlib_hexstr2buf(str, &aadlen); str = json_object_get_string(jmsg); ASSERT_NE(str, nullptr); pt = testlib_hexstr2buf(str, &ptlen); str = json_object_get_string(jct); ASSERT_NE(str, nullptr); ct = testlib_hexstr2buf(str, &ctlen); str = json_object_get_string(jresult); ASSERT_NE(str, nullptr); if (strcmp(str, "valid") == 0 || strcmp(str, "acceptable") == 0) valid = 1; else valid = 0; for (k = 0; k < (size_t)json_object_array_length(jflags); k++) { jtmp = json_object_array_get_idx(jflags, k); ASSERT_NE(jtmp, nullptr); str = json_object_get_string(jtmp); if (strcmp(str, "LongIv") == 0) ivlen0 = 1; else ivlen0 = 0; str = json_object_get_string(jtmp); if (strcmp(str, "InvalidNonceSize") == 0) nonce0 = 1; else nonce0 = 0; str = json_object_get_string(jtmp); if (strcmp(str, "InvalidTagSize") == 0) tag0 = 1; else tag0 = 0; } max = ptlen > ctlen ? ptlen : ctlen; pt_out = NULL; ct_out = NULL; if (max > 0) { pt_out = (unsigned char *)calloc(1, max); ASSERT_NE(pt_out, nullptr); ct_out = (unsigned char *)calloc(1, max); ASSERT_NE(ct_out, nullptr); } rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm, (ivlen0 || nonce0) ? (unsigned char *)1 : iv, ivsize / 8); EXPECT_EQ(rc, (ivlen0 || nonce0) ? ZPC_ERROR_IVSIZE : 0); if (!ivlen0 && !nonce0) { rc = zpc_aes_ccm_encrypt(aes_ccm, ct_out, tag_out, tagsize / 8, aad, aadlen, pt, ptlen); EXPECT_EQ(rc, tag0 ? ZPC_ERROR_TAGSIZE : 0); if (rc == 0) { EXPECT_TRUE(memcmp(ct_out, ct, ctlen) == 0); if (valid) { EXPECT_TRUE(memcmp(tag_out, tag, tagsize / 8) == 0); } } rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivsize / 8); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_decrypt(aes_ccm, pt_out, tag, tagsize / 8, aad, aadlen, ct, ctlen); EXPECT_EQ(rc, tag0 ? ZPC_ERROR_TAGSIZE : (valid ? 0 : ZPC_ERROR_TAGMISMATCH)); if (rc == 0) { EXPECT_TRUE(memcmp(pt_out, pt, ptlen) == 0); } } /* Unset key. */ rc = zpc_aes_ccm_set_key(aes_ccm, NULL); EXPECT_EQ(rc, 0); free(key); key = NULL; free(iv); iv = NULL; free(aad); aad = NULL; free(pt); pt = NULL; free(pt_out); pt_out = NULL; free(ct); ct = NULL; free(ct_out); ct_out = NULL; free(tag); tag = NULL; free(tag_out); tag_out = NULL; } } zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_ccm, rederive_protected_key1) { struct zpc_aes_key *aes_key1; struct zpc_aes_ccm *aes_ccm1, *aes_ccm2, *aes_ccm3; u8 iv[12], aad[99], m[99], tag[16], c[99]; /* use ivlen != 12 bytes such that it must be processed by kma */ int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); TESTLIB_AES_KERNEL_CAPS_CHECK(type); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm1); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm2); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm3); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_key(aes_ccm1, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_key(aes_ccm2, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_key(aes_ccm3, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); /* Random protected keys cannot be re-derived. */ rc = zpc_aes_key_set_mkvp(aes_key1, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); /* * This key obj has no type set. Therefore the generate will work also * for tests with ZPC_TEST_AES_KEY_TYPE = ZPC_AES_KEY_TYPE_PVSECRET. * The generated protected key has no dependency on any secure key or * pvsecret. */ rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_key(aes_ccm1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm1, iv, sizeof(iv)); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_key(aes_ccm2, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm2, iv, sizeof(iv)); EXPECT_EQ(rc, 0); memset(aes_ccm2->param_kma.protkey, 0, sizeof(aes_ccm2->param_kma.protkey)); memset(aes_ccm2->param_kmac.protkey, 0, sizeof(aes_ccm2->param_kmac.protkey)); rc = zpc_aes_ccm_encrypt(aes_ccm2, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); rc = zpc_aes_ccm_set_key(aes_ccm3, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_iv(aes_ccm3, iv, sizeof(iv)); EXPECT_EQ(rc, 0); memset(aes_ccm3->param_kma.protkey, 0, sizeof(aes_ccm3->param_kma.protkey)); memset(aes_ccm2->param_kma.protkey, 0, sizeof(aes_ccm2->param_kmac.protkey)); rc = zpc_aes_ccm_decrypt(aes_ccm3, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); rc = zpc_aes_ccm_set_key(aes_ccm1, aes_key1); EXPECT_EQ(rc, 0); zpc_aes_ccm_free(&aes_ccm3); zpc_aes_ccm_free(&aes_ccm2); zpc_aes_ccm_free(&aes_ccm1); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_ccm3, nullptr); EXPECT_EQ(aes_ccm2, nullptr); EXPECT_EQ(aes_ccm1, nullptr); EXPECT_EQ(aes_key1, nullptr); } TEST(aes_ccm, rederive_protected_key2) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); size_t keylen, ivlen, msglen, ctlen, taglen, aadlen; unsigned char buf[4096], mac[16] = { 0, }, pvsec_ct[4096]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_ccm *aes_ccm; unsigned int flags; int type, rc; const char *keystr = "e258b117c2fdd75587f07b400ae4af3e673a51dcf761e4ca"; const char *ivstr = "5ead03aa8c720d21b77075db"; const char *aadstr = "27702950960b9c79"; const char *msgstr = "afe96113a684bc52a6d962cf2724f6791d"; const char *ctstr = "7830446f333057d996a1a79b21c68d8b43"; const char *tagstr = "72ac478a66f5637563f1f12c1d0267ca"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 192, flags); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *aad = testlib_hexstr2buf(aadstr, &aadlen); ASSERT_NE(aad, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, keylen * 8); if (rc) goto ret; } /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, 0); memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_encrypt(aes_ccm, buf, mac, taglen, aad, aadlen, buf, msglen); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); } else { memcpy(pvsec_ct, buf, ctlen); } /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, 0); memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_encrypt(aes_ccm, buf, mac, taglen, aad, aadlen, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); } else { EXPECT_TRUE(memcmp(buf, pvsec_ct, ctlen) == 0); } /* Decrypt */ if (type != ZPC_AES_KEY_TYPE_PVSECRET) { memcpy(buf, ct, ctlen); } else { memcpy(buf, pvsec_ct, ctlen); memcpy(tag, mac, taglen); } memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_decrypt(aes_ccm, buf, tag, taglen, aad, aadlen, buf, ctlen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); /* Decrypt */ if (type != ZPC_AES_KEY_TYPE_PVSECRET) { memcpy(buf, ct, ctlen); } else { memcpy(buf, pvsec_ct, ctlen); memcpy(tag, mac, taglen); } memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_decrypt(aes_ccm, buf, tag, taglen, aad, aadlen, buf, ctlen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); ret: zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(iv); free(aad); free(msg); free(ct); free(tag); } TEST(aes_ccm, reencipher) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); size_t keylen, ivlen, msglen, ctlen, taglen, aadlen; unsigned char buf[4096], mac[16] = { 0, }; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_ccm *aes_ccm; unsigned int flags; int type, rc; const char *keystr = "e258b117c2fdd75587f07b400ae4af3e673a51dcf761e4ca"; const char *ivstr = "5ead03aa8c720d21b77075db"; const char *aadstr = "27702950960b9c79"; const char *msgstr = "afe96113a684bc52a6d962cf2724f6791d"; const char *ctstr = "7830446f333057d996a1a79b21c68d8b43"; const char *tagstr = "72ac478a66f5637563f1f12c1d0267ca"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 192, flags); TESTLIB_AES_NEW_MK_CHECK(type, mkvp, apqns); if (type == ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping reencipher test. Not applicable for UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *aad = testlib_hexstr2buf(aadstr, &aadlen); ASSERT_NE(aad, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_alloc(&aes_ccm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_reencipher(aes_key, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key->cur, 0, sizeof(aes_key->cur)); /* destroy current secure key */ /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_encrypt(aes_ccm, buf, mac, taglen, aad, aadlen, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_encrypt(aes_ccm, buf, mac, taglen, aad, aadlen, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_decrypt(aes_ccm, buf, tag, taglen, aad, aadlen, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_ccm->param_kma.protkey, 0, sizeof(aes_ccm->param_kma.protkey)); /* force WKaVP mismatch */ memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_decrypt(aes_ccm, buf, tag, taglen, aad, aadlen, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(iv); free(aad); free(msg); free(ct); free(tag); } static void __task(struct zpc_aes_key *aes_key) { struct zpc_aes_ccm *aes_ccm; unsigned char buf[4096], mac[16] = { 0, }; size_t ivlen, msglen, ctlen, taglen, aadlen; int rc, i; const char *ivstr = "5ead03aa8c720d21b77075db"; const char *aadstr = "27702950960b9c79"; const char *msgstr = "afe96113a684bc52a6d962cf2724f6791d"; const char *ctstr = "7830446f333057d996a1a79b21c68d8b43"; const char *tagstr = "72ac478a66f5637563f1f12c1d0267ca"; u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *aad = testlib_hexstr2buf(aadstr, &aadlen); ASSERT_NE(aad, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_ccm_alloc(&aes_ccm); EXPECT_EQ(rc, 0); rc = zpc_aes_ccm_set_key(aes_ccm, aes_key); EXPECT_EQ(rc, 0); for (i = 0; i < 1000; i++) { /* Encrypt */ memcpy(buf, msg, msglen); memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_encrypt(aes_ccm, buf, mac, taglen, aad, aadlen, buf, msglen); EXPECT_EQ(rc, 0); if (aes_key->type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); } /* Decrypt */ if (aes_key->type != ZPC_AES_KEY_TYPE_PVSECRET) { memcpy(buf, ct, ctlen); } else { memcpy(tag, mac, taglen); } rc = zpc_aes_ccm_set_iv(aes_ccm, iv, ivlen); EXPECT_EQ(rc, 0); memset(aes_ccm->param_kmac.protkey, 0, sizeof(aes_ccm->param_kmac.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ccm_decrypt(aes_ccm, buf, tag, taglen, aad, aadlen, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); } zpc_aes_ccm_free(&aes_ccm); EXPECT_EQ(aes_ccm, nullptr); free(iv); free(aad); free(msg); free(ct); free(tag); } TEST(aes_ccm, threads) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CCM_HW_CAPS_CHECK(); size_t keylen; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; unsigned int flags; int type, rc, i; std::thread *t[500]; const char *keystr = "e258b117c2fdd75587f07b400ae4af3e673a51dcf761e4ca"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 192, flags); TESTLIB_AES_NEW_MK_CHECK(type, mkvp, apqns); u8 *key = testlib_hexstr2buf(keystr, &keylen); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, keylen * 8); if (rc) goto ret; } for (i = 0; i < 500; i++) { t[i] = new std::thread(__task, aes_key); } /* Do something with key object while threads are working with it. */ if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_reencipher(aes_key, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key->cur, 0, sizeof(aes_key->cur)); /* destroy current secure key */ } for (i = 0; i < 500; i++) { memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ usleep(1); } for (i = 0; i < 500; i++) { t[i]->join(); delete t[i]; } ret: zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); } libzpc-1.3.0/test/t_aes_cmac.cc000066400000000000000000001023561475140344100163540ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "testlib.h" #include "gtest/gtest.h" #include "zpc/aes_cmac.h" #include "zpc/error.h" #include "aes_key_local.h" /* de-opaquify struct zpc_aes_key */ #include "aes_cmac_local.h" /* de-opaquify struct zpc_aes_cmac */ #include #include #include #include static void __run_json(const char *json); TEST(aes_cmac, alloc) { struct zpc_aes_cmac *aes_cmac; int rc; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CMAC_HW_CAPS_CHECK(); rc = zpc_aes_cmac_alloc(NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); aes_cmac = NULL; rc = zpc_aes_cmac_alloc(&aes_cmac); EXPECT_EQ(rc, 0); zpc_aes_cmac_free(&aes_cmac); EXPECT_EQ(aes_cmac, nullptr); aes_cmac = (struct zpc_aes_cmac *)&aes_cmac; rc = zpc_aes_cmac_alloc(&aes_cmac); EXPECT_EQ(rc, 0); zpc_aes_cmac_free(&aes_cmac); EXPECT_EQ(aes_cmac, nullptr); } TEST(aes_cmac, free) { struct zpc_aes_cmac *aes_cmac; int rc; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CMAC_HW_CAPS_CHECK(); zpc_aes_cmac_free(NULL); aes_cmac = NULL; zpc_aes_cmac_free(&aes_cmac); EXPECT_EQ(aes_cmac, nullptr); rc = zpc_aes_cmac_alloc(&aes_cmac); EXPECT_EQ(rc, 0); zpc_aes_cmac_free(&aes_cmac); EXPECT_EQ(aes_cmac, nullptr); } TEST(aes_cmac, set_key) { struct zpc_aes_key *aes_key; struct zpc_aes_cmac *aes_cmac; u8 clearkey[32]; unsigned int flags = 0; const char *mkvp, *apqns[257]; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CMAC_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_alloc(&aes_cmac); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_set_key(aes_cmac, aes_key); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, clearkey); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_cmac_set_key(NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_cmac_set_key(NULL, aes_key); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_cmac_set_key(aes_cmac, NULL); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_set_key(aes_cmac, aes_key); EXPECT_EQ(rc, 0); ret: zpc_aes_cmac_free(&aes_cmac); EXPECT_EQ(aes_cmac, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_cmac, sign) { struct zpc_aes_key *aes_key; struct zpc_aes_cmac *aes_cmac; const char *mkvp, *apqns[257]; u8 m[99], tag[16]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CMAC_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_alloc(&aes_cmac); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_cmac_set_key(aes_cmac, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac, tag, 16, m, 99); EXPECT_EQ(rc, 0); ret: zpc_aes_cmac_free(&aes_cmac); EXPECT_EQ(aes_cmac, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_cmac, verify) { struct zpc_aes_key *aes_key; struct zpc_aes_cmac *aes_cmac; const char *mkvp, *apqns[257]; u8 m[99], tag[16] = { 0, }; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CMAC_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_alloc(&aes_cmac); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_cmac_set_key(aes_cmac, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_verify(aes_cmac, tag, 16, m, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); ret: zpc_aes_cmac_free(&aes_cmac); EXPECT_EQ(aes_cmac, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_cmac, pc) { struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_cmac *aes_cmac1, *aes_cmac2; const char *mkvp, *apqns[257]; u8 m[99], tag[16], key[32]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CMAC_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_alloc(&aes_cmac1); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_alloc(&aes_cmac2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key1, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_cmac_set_key(aes_cmac1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key2, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key2, size); if (rc) goto ret; } rc = zpc_aes_cmac_set_key(aes_cmac2, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac1, tag, 16, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_verify(aes_cmac2, tag, 16, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac2, tag, 16, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_verify(aes_cmac1, tag, 16, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac2, tag, 16, m, 99); EXPECT_EQ(rc, 0); tag[0] ^= 1; rc = zpc_aes_cmac_verify(aes_cmac1, tag, 16, m, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); rc = zpc_aes_cmac_sign(aes_cmac1, tag, 16, m, 99); EXPECT_EQ(rc, 0); tag[0] ^= 1; rc = zpc_aes_cmac_verify(aes_cmac2, tag, 16, m, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); /* Random protected key */ rc = zpc_aes_cmac_set_key(aes_cmac1, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_set_key(aes_cmac2, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(aes_key1, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_cmac_set_key(aes_cmac1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_set_key(aes_cmac2, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac1, tag, 16, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_verify(aes_cmac2, tag, 16, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac2, tag, 16, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_verify(aes_cmac1, tag, 16, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac2, tag, 16, m, 99); EXPECT_EQ(rc, 0); tag[0] ^= 1; rc = zpc_aes_cmac_verify(aes_cmac1, tag, 16, m, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); rc = zpc_aes_cmac_sign(aes_cmac1, tag, 16, m, 99); EXPECT_EQ(rc, 0); tag[0] ^= 1; rc = zpc_aes_cmac_verify(aes_cmac2, tag, 16, m, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); ret: zpc_aes_cmac_free(&aes_cmac2); zpc_aes_cmac_free(&aes_cmac1); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); } TEST(aes_cmac, stream_inplace_kat1) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CMAC_HW_CAPS_CHECK(); size_t keylen, msglen, taglen; unsigned char mac[16]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_cmac *aes_cmac; unsigned int flags; int type, rc; const char *keystr = "648a44468d67bb6744b235ee7a3fcd6ed4bdc29ec5b5fa1a"; const char *msgstr = "c59d0d6981cca1be1d5519fc7881e6d230f39f6c12a9e827"; const char *tagstr = "a1b96272ae7f9aef567271795f21d1d3"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping stream_inplace_kat1 test. KATs cannot be performed with UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_alloc(&aes_cmac); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); /* Sign */ rc = zpc_aes_cmac_set_key(aes_cmac, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac, mac, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); rc = zpc_aes_cmac_sign(aes_cmac, mac, taglen, msg, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Verify */ rc = zpc_aes_cmac_verify(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_verify(aes_cmac, tag, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_verify(aes_cmac, tag, taglen, msg, msglen); EXPECT_EQ(rc, 0); zpc_aes_cmac_free(&aes_cmac); EXPECT_EQ(aes_cmac, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(msg); free(tag); } TEST(aes_cmac, stream_inplace_kat2) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CMAC_HW_CAPS_CHECK(); size_t keylen, msglen, taglen; unsigned char mac[16]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_cmac *aes_cmac; unsigned int flags; int type, rc; const char *keystr = "648a44468d67bb6744b235ee7a3fcd6ed4bdc29ec5b5fa1a"; const char *msgstr = "c59d0d6981cca1be1d5519fc7881e6d230f39f6c12a9e827"; const char *tagstr = "a1b96272ae7f9aef567271795f21d1d3"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping stream_inplace_kat2 test. KATs cannot be performed with UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_alloc(&aes_cmac); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); /* Sign */ rc = zpc_aes_cmac_set_key(aes_cmac, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac, NULL, 0, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac, mac, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Verify */ rc = zpc_aes_cmac_verify(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_verify(aes_cmac, NULL, 0, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_verify(aes_cmac, tag, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); zpc_aes_cmac_free(&aes_cmac); EXPECT_EQ(aes_cmac, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(msg); free(tag); } TEST(aes_cmac, wycheproof_kat) { int type; type = testlib_env_aes_key_type(); TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CMAC_HW_CAPS_CHECK(); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping wycheproof_kat test. KATs cannot be performed with UV secrets."); __run_json("wycheproof/src/wycheproof/testvectors/aes_cmac_test.json"); } static void __run_json(const char *json) { const char *tv = json, *str; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_cmac *aes_cmac; unsigned int flags; u8 *key = NULL; u8 *pt = NULL; u8 *tag = NULL, *tag_out = NULL; int rc, tagsize = 0, keysize = 0; int valid = 0; size_t ptlen, taglen, i, j; json_object *jkey, *jtag, *jmsg, *jresult, *jtmp, *jtestgroups, *jfile, *jkeysize, *jtagsize, *jtests; json_bool b; int type; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_alloc(&aes_cmac); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); jfile = json_object_from_file(tv); ASSERT_NE(jfile, nullptr); b = json_object_object_get_ex(jfile, "testGroups", &jtestgroups); ASSERT_TRUE(b); for (i = 0; i < (size_t)json_object_array_length(jtestgroups); i++) { jtmp = json_object_array_get_idx(jtestgroups, i); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "keySize", &jkeysize); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "tagSize", &jtagsize); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "tests", &jtests); ASSERT_TRUE(b); keysize = json_object_get_int(jkeysize); tagsize = json_object_get_int(jtagsize); rc = zpc_aes_key_set_size(aes_key, keysize); if (keysize != 128 && keysize != 192 && keysize != 256) { EXPECT_EQ(rc, ZPC_ERROR_KEYSIZE); continue; } else { EXPECT_EQ(rc, 0); } for (j = 0; j < (size_t)json_object_array_length(jtests); j++) { jtmp = json_object_array_get_idx(jtests, j); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "key", &jkey); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "tag", &jtag); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "msg", &jmsg); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "result", &jresult); ASSERT_TRUE(b); str = json_object_get_string(jkey); ASSERT_NE(str, nullptr); key = testlib_hexstr2buf(str, NULL); ASSERT_NE(key, nullptr); str = json_object_get_string(jtag); ASSERT_NE(str, nullptr); tag = testlib_hexstr2buf(str, &taglen); ASSERT_NE(tag, nullptr); tag_out = (unsigned char *)calloc(1, taglen); ASSERT_NE(tag_out, nullptr); str = json_object_get_string(jmsg); ASSERT_NE(str, nullptr); pt = testlib_hexstr2buf(str, &ptlen); str = json_object_get_string(jresult); ASSERT_NE(str, nullptr); if (strcmp(str, "valid") == 0) valid = 1; else if (strcmp(str, "invalid") == 0) valid = 0; else assert(strcmp(str, "invalid") == 0 || strcmp(str, "valid") == 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_set_key(aes_cmac, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac, tag_out, tagsize / 8, pt, ptlen); EXPECT_EQ(rc, 0); if (valid) { EXPECT_TRUE(memcmp(tag_out, tag, tagsize / 8) == 0); } rc = zpc_aes_cmac_verify(aes_cmac, tag, tagsize / 8, pt, ptlen); EXPECT_EQ(rc, valid ? 0 : ZPC_ERROR_TAGMISMATCH); /* Unset key. */ rc = zpc_aes_cmac_set_key(aes_cmac, NULL); EXPECT_EQ(rc, 0); free(key); key = NULL; free(pt); pt = NULL; free(tag); tag = NULL; free(tag_out); tag_out = NULL; } } zpc_aes_cmac_free(&aes_cmac); EXPECT_EQ(aes_cmac, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_cmac, rederive_protected_key1) { struct zpc_aes_key *aes_key1; struct zpc_aes_cmac *aes_cmac1, *aes_cmac2, *aes_cmac3; u8 m[99], tag[16]; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CMAC_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); TESTLIB_AES_KERNEL_CAPS_CHECK(type); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_alloc(&aes_cmac1); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_alloc(&aes_cmac2); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_alloc(&aes_cmac3); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_set_key(aes_cmac1, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_set_key(aes_cmac2, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_set_key(aes_cmac3, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); /* Random protected keys cannot be re-derived. */ rc = zpc_aes_key_set_mkvp(aes_key1, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); /* * This key obj has no type set. Therefore the generate will work also * for tests with ZPC_TEST_AES_KEY_TYPE = ZPC_AES_KEY_TYPE_PVSECRET. * The generated protected key has no dependency on any secure key or * pvsecret. */ rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_set_key(aes_cmac1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_set_key(aes_cmac2, aes_key1); EXPECT_EQ(rc, 0); memset(aes_cmac2->param_kmac.protkey, 0, sizeof(aes_cmac2->param_kmac.protkey)); memset(aes_cmac2->param_pcc.protkey, 0, sizeof(aes_cmac2->param_pcc.protkey)); rc = zpc_aes_cmac_sign(aes_cmac2, tag, 16, m, 99); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); rc = zpc_aes_cmac_set_key(aes_cmac3, aes_key1); EXPECT_EQ(rc, 0); memset(aes_cmac3->param_kmac.protkey, 0, sizeof(aes_cmac3->param_kmac.protkey)); memset(aes_cmac2->param_pcc.protkey, 0, sizeof(aes_cmac2->param_pcc.protkey)); rc = zpc_aes_cmac_verify(aes_cmac3, tag, 16, m, 99); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); rc = zpc_aes_cmac_set_key(aes_cmac1, aes_key1); EXPECT_EQ(rc, 0); zpc_aes_cmac_free(&aes_cmac3); zpc_aes_cmac_free(&aes_cmac2); zpc_aes_cmac_free(&aes_cmac1); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_cmac3, nullptr); EXPECT_EQ(aes_cmac2, nullptr); EXPECT_EQ(aes_cmac1, nullptr); EXPECT_EQ(aes_key1, nullptr); } TEST(aes_cmac, rederive_protected_key2) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CMAC_HW_CAPS_CHECK(); size_t keylen, msglen, taglen; unsigned char mac[16]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_cmac *aes_cmac; unsigned int flags; int type, rc; const char *keystr = "648a44468d67bb6744b235ee7a3fcd6ed4bdc29ec5b5fa1a"; const char *msgstr = "c59d0d6981cca1be1d5519fc7881e6d230f39f6c12a9e827"; const char *tagstr = "a1b96272ae7f9aef567271795f21d1d3"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 192, flags); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_alloc(&aes_cmac); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, keylen * 8); if (rc) goto ret; } /* Sign */ rc = zpc_aes_cmac_set_key(aes_cmac, aes_key); EXPECT_EQ(rc, 0); memset(aes_cmac->param_kmac.protkey, 0, sizeof(aes_cmac->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_cmac->param_pcc.protkey, 0, sizeof(aes_cmac->param_pcc.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cmac_sign(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac, mac, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); } /* Sign*/ memset(aes_cmac->param_kmac.protkey, 0, sizeof(aes_cmac->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_cmac->param_pcc.protkey, 0, sizeof(aes_cmac->param_pcc.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cmac_sign(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); memset(aes_cmac->param_kmac.protkey, 0, sizeof(aes_cmac->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_cmac->param_pcc.protkey, 0, sizeof(aes_cmac->param_pcc.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cmac_sign(aes_cmac, mac, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); } /* Verify */ rc = zpc_aes_cmac_verify(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); memset(aes_cmac->param_kmac.protkey, 0, sizeof(aes_cmac->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_cmac->param_pcc.protkey, 0, sizeof(aes_cmac->param_pcc.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cmac_verify(aes_cmac, mac, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); /* Verify */ memset(aes_cmac->param_kmac.protkey, 0, sizeof(aes_cmac->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_cmac->param_pcc.protkey, 0, sizeof(aes_cmac->param_pcc.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cmac_verify(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_verify(aes_cmac, mac, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); ret: zpc_aes_cmac_free(&aes_cmac); EXPECT_EQ(aes_cmac, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(msg); free(tag); } TEST(aes_cmac, reencipher) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CMAC_HW_CAPS_CHECK(); size_t keylen, msglen, taglen; unsigned char mac[16]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_cmac *aes_cmac; unsigned int flags; int type, rc; const char *keystr = "648a44468d67bb6744b235ee7a3fcd6ed4bdc29ec5b5fa1a"; const char *msgstr = "c59d0d6981cca1be1d5519fc7881e6d230f39f6c12a9e827"; const char *tagstr = "a1b96272ae7f9aef567271795f21d1d3"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 192, flags); TESTLIB_AES_NEW_MK_CHECK(type, mkvp, apqns); if (type == ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping reencipher test. Not applicable for UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_alloc(&aes_cmac); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_reencipher(aes_key, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key->cur, 0, sizeof(aes_key->cur)); /* destroy current secure key */ /* Encrypt */ rc = zpc_aes_cmac_set_key(aes_cmac, aes_key); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cmac->param_kmac.protkey, 0, sizeof(aes_cmac->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_cmac->param_pcc.protkey, 0, sizeof(aes_cmac->param_pcc.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cmac_sign(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac, mac, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Encrypt */ rc = zpc_aes_cmac_set_key(aes_cmac, aes_key); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cmac->param_kmac.protkey, 0, sizeof(aes_cmac->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_cmac->param_pcc.protkey, 0, sizeof(aes_cmac->param_pcc.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cmac_sign(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cmac->param_pcc.protkey, 0, sizeof(aes_cmac->param_pcc.protkey)); /* force WKaVP mismatch */ memset(aes_cmac->param_kmac.protkey, 0, sizeof(aes_cmac->param_kmac.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cmac_sign(aes_cmac, mac, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Decrypt */ rc = zpc_aes_cmac_verify(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cmac->param_kmac.protkey, 0, sizeof(aes_cmac->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_cmac->param_pcc.protkey, 0, sizeof(aes_cmac->param_pcc.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cmac_verify(aes_cmac, mac, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); /* Decrypt */ memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_cmac->param_kmac.protkey, 0, sizeof(aes_cmac->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_cmac->param_pcc.protkey, 0, sizeof(aes_cmac->param_pcc.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cmac_verify(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_verify(aes_cmac, mac, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); zpc_aes_cmac_free(&aes_cmac); EXPECT_EQ(aes_cmac, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(msg); free(tag); } static void __task(struct zpc_aes_key *aes_key) { struct zpc_aes_cmac *aes_cmac; unsigned char mac[16]; size_t msglen, taglen; int rc, i; const char *msgstr = "c59d0d6981cca1be1d5519fc7881e6d230f39f6c12a9e827"; const char *tagstr = "a1b96272ae7f9aef567271795f21d1d3"; u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_cmac_alloc(&aes_cmac); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_set_key(aes_cmac, aes_key); EXPECT_EQ(rc, 0); for (i = 0; i < 1000; i++) { /* Sign */ memset(aes_cmac->param_kmac.protkey, 0, sizeof(aes_cmac->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_cmac->param_pcc.protkey, 0, sizeof(aes_cmac->param_pcc.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cmac_sign(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_sign(aes_cmac, mac, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); if (aes_key->type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); } /* Verify */ memset(aes_cmac->param_kmac.protkey, 0, sizeof(aes_cmac->param_kmac.protkey)); /* force WKaVP mismatch */ memset(aes_cmac->param_pcc.protkey, 0, sizeof(aes_cmac->param_pcc.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_cmac_verify(aes_cmac, NULL, 0, msg, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_cmac_verify(aes_cmac, mac, taglen, msg + 16, msglen - 16); EXPECT_EQ(rc, 0); } zpc_aes_cmac_free(&aes_cmac); EXPECT_EQ(aes_cmac, nullptr); free(msg); free(tag); } TEST(aes_cmac, threads) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_CMAC_HW_CAPS_CHECK(); size_t keylen; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; unsigned int flags; int type, rc, i; std::thread *t[500]; const char *keystr = "648a44468d67bb6744b235ee7a3fcd6ed4bdc29ec5b5fa1a"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 192, flags); TESTLIB_AES_NEW_MK_CHECK(type, mkvp, apqns); u8 *key = testlib_hexstr2buf(keystr, &keylen); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, keylen * 8); if (rc) goto ret; } for (i = 0; i < 500; i++) { t[i] = new std::thread(__task, aes_key); } /* Do something with key object while threads are working with it. */ if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_reencipher(aes_key, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key->cur, 0, sizeof(aes_key->cur)); /* destroy current secure key */ } for (i = 0; i < 500; i++) { memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ usleep(1); } for (i = 0; i < 500; i++) { t[i]->join(); delete t[i]; } ret: zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); } libzpc-1.3.0/test/t_aes_ecb.cc000066400000000000000000000724231475140344100162030ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "testlib.h" #include "gtest/gtest.h" #include "zpc/aes_ecb.h" #include "zpc/error.h" #include "aes_key_local.h" /* de-opaquify struct zpc_aes_key */ #include "aes_ecb_local.h" /* de-opaquify struct zpc_aes_ecb */ #include #include #include #include static void __run_json(const char *json); TEST(aes_ecb, alloc) { struct zpc_aes_ecb *aes_ecb; int rc; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_ECB_HW_CAPS_CHECK(); rc = zpc_aes_ecb_alloc(NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); aes_ecb = NULL; rc = zpc_aes_ecb_alloc(&aes_ecb); EXPECT_EQ(rc, 0); zpc_aes_ecb_free(&aes_ecb); EXPECT_EQ(aes_ecb, nullptr); aes_ecb = (struct zpc_aes_ecb *)&aes_ecb; rc = zpc_aes_ecb_alloc(&aes_ecb); EXPECT_EQ(rc, 0); zpc_aes_ecb_free(&aes_ecb); EXPECT_EQ(aes_ecb, nullptr); } TEST(aes_ecb, free) { struct zpc_aes_ecb *aes_ecb; int rc; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_ECB_HW_CAPS_CHECK(); zpc_aes_ecb_free(NULL); aes_ecb = NULL; zpc_aes_ecb_free(&aes_ecb); EXPECT_EQ(aes_ecb, nullptr); rc = zpc_aes_ecb_alloc(&aes_ecb); EXPECT_EQ(rc, 0); zpc_aes_ecb_free(&aes_ecb); EXPECT_EQ(aes_ecb, nullptr); } TEST(aes_ecb, set_key) { struct zpc_aes_key *aes_key; struct zpc_aes_ecb *aes_ecb; u8 clearkey[32]; unsigned int flags = 0; const char *mkvp, *apqns[257]; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_ECB_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_alloc(&aes_ecb); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_set_key(aes_ecb, aes_key); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, clearkey); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_ecb_set_key(NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_ecb_set_key(NULL, aes_key); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_ecb_set_key(aes_ecb, NULL); EXPECT_EQ(rc, 0); ret: zpc_aes_ecb_free(&aes_ecb); EXPECT_EQ(aes_ecb, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_ecb, encrypt) { struct zpc_aes_key *aes_key; struct zpc_aes_ecb *aes_ecb; const char *mkvp, *apqns[257]; u8 m[64], c[64]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_ECB_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_alloc(&aes_ecb); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_ecb_set_key(aes_ecb, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_encrypt(aes_ecb, c, m, 64); EXPECT_EQ(rc, 0); ret: zpc_aes_ecb_free(&aes_ecb); EXPECT_EQ(aes_ecb, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_ecb, decrypt) { struct zpc_aes_key *aes_key; struct zpc_aes_ecb *aes_ecb; const char *mkvp, *apqns[257]; u8 m[64], c[64]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_ECB_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_alloc(&aes_ecb); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_ecb_set_key(aes_ecb, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_decrypt(aes_ecb, m, c, 64); EXPECT_EQ(rc, 0); ret: zpc_aes_ecb_free(&aes_ecb); EXPECT_EQ(aes_ecb, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_ecb, pc) { struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_ecb *aes_ecb1, *aes_ecb2; const char *mkvp, *apqns[257]; u8 m[80], c[80], key[32], m_bak[80]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_ECB_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); memcpy(m_bak, m, 80); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_alloc(&aes_ecb1); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_alloc(&aes_ecb2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key1, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_ecb_set_key(aes_ecb1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key2, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key2, size); if (rc) goto ret; } rc = zpc_aes_ecb_set_key(aes_ecb2, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_encrypt(aes_ecb1, c, m, 80); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_decrypt(aes_ecb2, m, c, 80); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 80) == 0); rc = zpc_aes_ecb_encrypt(aes_ecb2, c, m, 80); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_decrypt(aes_ecb1, m, c, 80); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 80) == 0); /* Random protected key */ rc = zpc_aes_ecb_set_key(aes_ecb1, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_set_key(aes_ecb2, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(aes_key1, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_ecb_set_key(aes_ecb1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_set_key(aes_ecb2, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_encrypt(aes_ecb1, c, m, 80); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_decrypt(aes_ecb2, m, c, 80); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 80) == 0); rc = zpc_aes_ecb_encrypt(aes_ecb2, c, m, 80); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_decrypt(aes_ecb1, m, c, 80); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 80) == 0); ret: zpc_aes_ecb_free(&aes_ecb2); zpc_aes_ecb_free(&aes_ecb1); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); } TEST(aes_ecb, stream_inplace_kat) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_ECB_HW_CAPS_CHECK(); size_t keylen, msglen, ctlen; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_ecb *aes_ecb; unsigned int flags; int type, rc; const char *keystr = "605c4139c961b496ca5148f1bdb1bb1901f2101943a0ec10fcdc403d3b0c285a"; const char *msgstr = "68c9885ba2be03181f65f1e04e83d6ba6880467550bcf099be26dc9d9c0af15ab02abac07c116ac862a41da90cfa604f"; const char *ctstr = "a7603d29bbba4c77208bf2f3df9f5ec85204adce012299f2cce7b326ce78f5cf8040343dd291e8cf9f3645726368dc20"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping stream_inplace_kat test. KATs cannot be performed with UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_alloc(&aes_ecb); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_set_key(aes_ecb, aes_key); EXPECT_EQ(rc, 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_ecb_encrypt(aes_ecb, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_encrypt(aes_ecb, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_ecb_encrypt(aes_ecb, buf, buf, 32); rc = zpc_aes_ecb_encrypt(aes_ecb, buf + 32, buf + 32, msglen - 32); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_ecb_decrypt(aes_ecb, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_decrypt(aes_ecb, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_ecb_decrypt(aes_ecb, buf, buf, 32); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_decrypt(aes_ecb, buf + 32, buf + 32, msglen - 32); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_ecb_free(&aes_ecb); EXPECT_EQ(aes_ecb, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(msg); free(ct); } TEST(aes_ecb, nist_kat) { int type; type = testlib_env_aes_key_type(); TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_ECB_HW_CAPS_CHECK(); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping nist_kat test. KATs cannot be performed with UV secrets."); __run_json("nist_aes_ecb.json"); } static void __run_json(const char *json) { const char *tv = json, *str; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_ecb *aes_ecb; unsigned int flags; u8 *key = NULL; u8 *pt = NULL, *pt_out = NULL, *ct = NULL, *ct_out = NULL; int rc, keysize = 0; size_t ptlen, ctlen, i, j, max; json_object *jkey, *jmsg, *jct, *jtmp, *jtestgroups, *jfile, *jkeysize, *jtests; json_bool b; int type; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_alloc(&aes_ecb); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); jfile = json_object_from_file(tv); ASSERT_NE(jfile, nullptr); b = json_object_object_get_ex(jfile, "testGroups", &jtestgroups); ASSERT_TRUE(b); for (i = 0; i < (size_t)json_object_array_length(jtestgroups); i++) { jtmp = json_object_array_get_idx(jtestgroups, i); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "keySize", &jkeysize); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "tests", &jtests); ASSERT_TRUE(b); keysize = json_object_get_int(jkeysize); rc = zpc_aes_key_set_size(aes_key, keysize); EXPECT_EQ(rc, 0); for (j = 0; j < (size_t)json_object_array_length(jtests); j++) { jtmp = json_object_array_get_idx(jtests, j); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "key", &jkey); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "msg", &jmsg); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "ct", &jct); ASSERT_TRUE(b); str = json_object_get_string(jkey); ASSERT_NE(str, nullptr); key = testlib_hexstr2buf(str, NULL); ASSERT_NE(key, nullptr); str = json_object_get_string(jmsg); ASSERT_NE(str, nullptr); pt = testlib_hexstr2buf(str, &ptlen); str = json_object_get_string(jct); ASSERT_NE(str, nullptr); ct = testlib_hexstr2buf(str, &ctlen); max = ptlen > ctlen ? ptlen : ctlen; pt_out = NULL; ct_out = NULL; if (max > 0) { pt_out = (unsigned char *)calloc(1, max); ASSERT_NE(pt_out, nullptr); ct_out = (unsigned char *)calloc(1, max); ASSERT_NE(ct_out, nullptr); } rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_set_key(aes_ecb, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_decrypt(aes_ecb, pt_out, ct, ctlen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(pt_out, pt, ptlen) == 0); rc = zpc_aes_ecb_encrypt(aes_ecb, ct_out, pt, ptlen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(ct_out, ct, ctlen) == 0); /* Unset key. */ rc = zpc_aes_ecb_set_key(aes_ecb, NULL); EXPECT_EQ(rc, 0); free(key); key = NULL; free(pt); pt = NULL; free(pt_out); pt_out = NULL; free(ct); ct = NULL; free(ct_out); ct_out = NULL; } } zpc_aes_ecb_free(&aes_ecb); EXPECT_EQ(aes_ecb, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_ecb, rederive_protected_key1) { struct zpc_aes_key *aes_key1; struct zpc_aes_ecb *aes_ecb1, *aes_ecb2, *aes_ecb3; u8 m[96], c[96]; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_ECB_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); TESTLIB_AES_KERNEL_CAPS_CHECK(type); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_alloc(&aes_ecb1); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_alloc(&aes_ecb2); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_alloc(&aes_ecb3); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_set_key(aes_ecb1, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_set_key(aes_ecb2, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_set_key(aes_ecb3, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); /* Random protected keys cannot be re-derived. */ rc = zpc_aes_key_set_mkvp(aes_key1, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); /* * This key obj has no type set. Therefore the generate will work also * for tests with ZPC_TEST_AES_KEY_TYPE = ZPC_AES_KEY_TYPE_PVSECRET. * The generated protected key has no dependency on any secure key or * pvsecret. */ rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_set_key(aes_ecb1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_set_key(aes_ecb2, aes_key1); EXPECT_EQ(rc, 0); memset(aes_ecb2->param.protkey, 0, sizeof(aes_ecb2->param.protkey)); rc = zpc_aes_ecb_encrypt(aes_ecb2, c, m, 96); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); rc = zpc_aes_ecb_set_key(aes_ecb3, aes_key1); EXPECT_EQ(rc, 0); memset(aes_ecb3->param.protkey, 0, sizeof(aes_ecb3->param.protkey)); rc = zpc_aes_ecb_decrypt(aes_ecb3, m, c, 96); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); zpc_aes_ecb_free(&aes_ecb3); zpc_aes_ecb_free(&aes_ecb2); zpc_aes_ecb_free(&aes_ecb1); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_ecb3, nullptr); EXPECT_EQ(aes_ecb2, nullptr); EXPECT_EQ(aes_ecb1, nullptr); EXPECT_EQ(aes_key1, nullptr); } TEST(aes_ecb, rederive_protected_key2) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_ECB_HW_CAPS_CHECK(); size_t keylen, msglen, ctlen; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_ecb *aes_ecb; unsigned int flags; int type, rc; const char *keystr = "605c4139c961b496ca5148f1bdb1bb1901f2101943a0ec10fcdc403d3b0c285a"; const char *msgstr = "68c9885ba2be03181f65f1e04e83d6ba6880467550bcf099be26dc9d9c0af15ab02abac07c116ac862a41da90cfa604f"; const char *ctstr = "a7603d29bbba4c77208bf2f3df9f5ec85204adce012299f2cce7b326ce78f5cf8040343dd291e8cf9f3645726368dc20"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_alloc(&aes_ecb); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, keylen * 8); if (rc) goto ret; } /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_ecb_set_key(aes_ecb, aes_key); EXPECT_EQ(rc, 0); memset(aes_ecb->param.protkey, 0, sizeof(aes_ecb->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ecb_encrypt(aes_ecb, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_encrypt(aes_ecb, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); } /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_ecb_set_key(aes_ecb, aes_key); EXPECT_EQ(rc, 0); memset(aes_ecb->param.protkey, 0, sizeof(aes_ecb->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ecb_encrypt(aes_ecb, buf, buf, 16); EXPECT_EQ(rc, 0); memset(aes_ecb->param.protkey, 0, sizeof(aes_ecb->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ecb_encrypt(aes_ecb, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); } /* Decrypt */ memcpy(buf, ct, ctlen); memset(aes_ecb->param.protkey, 0, sizeof(aes_ecb->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ecb_decrypt(aes_ecb, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_decrypt(aes_ecb, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); } /* Decrypt */ memcpy(buf, ct, ctlen); memset(aes_ecb->param.protkey, 0, sizeof(aes_ecb->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ecb_decrypt(aes_ecb, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_decrypt(aes_ecb, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); } ret: zpc_aes_ecb_free(&aes_ecb); EXPECT_EQ(aes_ecb, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(msg); free(ct); } TEST(aes_ecb, reencipher) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_ECB_HW_CAPS_CHECK(); size_t keylen, msglen, ctlen; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_ecb *aes_ecb; unsigned int flags; int type, rc; const char *keystr = "605c4139c961b496ca5148f1bdb1bb1901f2101943a0ec10fcdc403d3b0c285a"; const char *msgstr = "68c9885ba2be03181f65f1e04e83d6ba6880467550bcf099be26dc9d9c0af15ab02abac07c116ac862a41da90cfa604f"; const char *ctstr = "a7603d29bbba4c77208bf2f3df9f5ec85204adce012299f2cce7b326ce78f5cf8040343dd291e8cf9f3645726368dc20"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); TESTLIB_AES_NEW_MK_CHECK(type, mkvp, apqns); if (type == ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping reencipher test. Not applicable for UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_alloc(&aes_ecb); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_reencipher(aes_key, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key->cur, 0, sizeof(aes_key->cur)); /* destroy current secure key */ /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_ecb_set_key(aes_ecb, aes_key); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_ecb->param.protkey, 0, sizeof(aes_ecb->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ecb_encrypt(aes_ecb, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_encrypt(aes_ecb, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_ecb_set_key(aes_ecb, aes_key); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_ecb->param.protkey, 0, sizeof(aes_ecb->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ecb_encrypt(aes_ecb, buf, buf, 16); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_ecb->param.protkey, 0, sizeof(aes_ecb->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ecb_encrypt(aes_ecb, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_ecb->param.protkey, 0, sizeof(aes_ecb->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ecb_decrypt(aes_ecb, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_decrypt(aes_ecb, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_ecb->param.protkey, 0, sizeof(aes_ecb->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ecb_decrypt(aes_ecb, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_decrypt(aes_ecb, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_ecb_free(&aes_ecb); EXPECT_EQ(aes_ecb, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(msg); free(ct); } static void __task(struct zpc_aes_key *aes_key) { struct zpc_aes_ecb *aes_ecb; unsigned char buf[4096]; size_t msglen, ctlen; int rc, i; const char *msgstr = "68c9885ba2be03181f65f1e04e83d6ba6880467550bcf099be26dc9d9c0af15ab02abac07c116ac862a41da90cfa604f"; const char *ctstr = "a7603d29bbba4c77208bf2f3df9f5ec85204adce012299f2cce7b326ce78f5cf8040343dd291e8cf9f3645726368dc20"; u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_ecb_alloc(&aes_ecb); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_set_key(aes_ecb, aes_key); EXPECT_EQ(rc, 0); for (i = 0; i < 1000; i++) { /* Encrypt */ memcpy(buf, msg, msglen); memset(aes_ecb->param.protkey, 0, sizeof(aes_ecb->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ecb_encrypt(aes_ecb, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_encrypt(aes_ecb, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); if (aes_key->type != ZPC_AES_KEY_TYPE_PVSECRET) { /* The pvsecret key is not the KAT key */ EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); } /* Decrypt */ if (aes_key->type != ZPC_AES_KEY_TYPE_PVSECRET) { memcpy(buf, ct, ctlen); } memset(aes_ecb->param.protkey, 0, sizeof(aes_ecb->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_ecb_decrypt(aes_ecb, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_ecb_decrypt(aes_ecb, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); } zpc_aes_ecb_free(&aes_ecb); EXPECT_EQ(aes_ecb, nullptr); free(msg); free(ct); } TEST(aes_ecb, threads) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_ECB_HW_CAPS_CHECK(); size_t keylen; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; unsigned int flags; int type, rc, i; std::thread *t[500]; const char *keystr = "605c4139c961b496ca5148f1bdb1bb1901f2101943a0ec10fcdc403d3b0c285a"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); TESTLIB_AES_NEW_MK_CHECK(type, mkvp, apqns); u8 *key = testlib_hexstr2buf(keystr, &keylen); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, keylen * 8); if (rc) goto ret; } for (i = 0; i < 500; i++) { t[i] = new std::thread(__task, aes_key); } /* Do something with key object while threads are working with it. */ if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_reencipher(aes_key, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key->cur, 0, sizeof(aes_key->cur)); /* destroy current secure key */ } for (i = 0; i < 500; i++) { memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ usleep(1); } for (i = 0; i < 500; i++) { t[i]->join(); delete t[i]; } ret: zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); } libzpc-1.3.0/test/t_aes_gcm.cc000066400000000000000000001565051475140344100162240ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "testlib.h" #include "gtest/gtest.h" #include "zpc/aes_gcm.h" #include "zpc/error.h" #include "aes_key_local.h" /* de-opaquify struct zpc_aes_key */ #include "aes_gcm_local.h" /* de-opaquify struct zpc_aes_gcm */ #include #include #include #include static void __run_json(const char *json); TEST(aes_gcm, alloc) { struct zpc_aes_gcm *aes_gcm; int rc; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); rc = zpc_aes_gcm_alloc(NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); aes_gcm = NULL; rc = zpc_aes_gcm_alloc(&aes_gcm); EXPECT_EQ(rc, 0); zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); aes_gcm = (struct zpc_aes_gcm *)&aes_gcm; rc = zpc_aes_gcm_alloc(&aes_gcm); EXPECT_EQ(rc, 0); zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); } TEST(aes_gcm, free) { struct zpc_aes_gcm *aes_gcm; int rc; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); zpc_aes_gcm_free(NULL); aes_gcm = NULL; zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); rc = zpc_aes_gcm_alloc(&aes_gcm); EXPECT_EQ(rc, 0); zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); } TEST(aes_gcm, set_key) { struct zpc_aes_key *aes_key; struct zpc_aes_gcm *aes_gcm; u8 clearkey[32], iv[12]; unsigned int flags = 0; const char *mkvp, *apqns[257]; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, clearkey); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_gcm_set_key(NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_gcm_set_key(NULL, aes_key); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_gcm_set_key(aes_gcm, NULL); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, 12); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, 12); EXPECT_EQ(rc, 0); ret: zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_gcm, set_iv) { struct zpc_aes_key *aes_key; struct zpc_aes_gcm *aes_gcm; const char *mkvp, *apqns[257]; u8 iv[16]; int rc, size, type; unsigned int flags; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(NULL, NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_gcm_set_iv(NULL, iv, 12); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_gcm_set_iv(aes_gcm, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, 12); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_gcm_set_iv(aes_gcm, iv, 12); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, 0); EXPECT_EQ(rc, ZPC_ERROR_IVSIZE); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, SIZE_MAX); EXPECT_EQ(rc, ZPC_ERROR_IVSIZE); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, 16); EXPECT_EQ(rc, 0); ret: zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_gcm, create_iv) { struct zpc_aes_key *aes_key; struct zpc_aes_gcm *aes_gcm1, *aes_gcm2; const char *mkvp, *apqns[257]; u8 aad[99], m[99], tag[16], tmp_tag[16], buf[99], pt[99]; u8 iv_buf[4096]; int rc, size, type; unsigned int flags; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm1); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm2); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_create_iv(aes_gcm1, iv_buf, 0); EXPECT_EQ(rc, ZPC_ERROR_IVSIZE); rc = zpc_aes_gcm_create_iv(aes_gcm1, iv_buf, 1234); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_gcm_set_key(aes_gcm1, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_key(aes_gcm2, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_create_iv(aes_gcm1, iv_buf, SIZE_MAX); EXPECT_EQ(rc, ZPC_ERROR_IVSIZE); rc = zpc_aes_gcm_create_iv(aes_gcm1, iv_buf, 11); EXPECT_EQ(rc, ZPC_ERROR_IVSIZE); rc = zpc_aes_gcm_create_iv(aes_gcm1, iv_buf, 12); EXPECT_EQ(rc, 0); /* Create internal iv for encrypt/decrypt */ rc = zpc_aes_gcm_create_iv(aes_gcm1, iv_buf, 1234); EXPECT_EQ(rc, 0); /* Encrypt in-place with internally created iv */ rc = zpc_aes_gcm_encrypt(aes_gcm1, buf, tag, sizeof(tag), aad, sizeof(aad), m, sizeof(m)); EXPECT_EQ(rc, 0); /* * Try to use set_iv on first ctx with already created internal iv. This * fails because it is not allowed to overwrite an internal iv. */ rc = zpc_aes_gcm_set_iv(aes_gcm1, iv_buf, 78); EXPECT_EQ(rc, ZPC_ERROR_GCM_IV_CREATED_INTERNALLY); /* * Try to use same ctx for decrypt: this fails, because the initial iv * is not available because set_iv is not allowed on this ctx after * creating an internal iv. */ memcpy(tmp_tag, tag, sizeof(tag)); rc = zpc_aes_gcm_decrypt(aes_gcm1, pt, tmp_tag, sizeof(tmp_tag), aad, sizeof(aad), buf, sizeof(buf)); EXPECT_EQ(rc, ZPC_ERROR_GCM_IV_CREATED_INTERNALLY); /* Decrypt in-place with internally created iv and 2nd ctx */ rc = zpc_aes_gcm_set_iv(aes_gcm2, iv_buf, 1234); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm2, pt, tag, sizeof(tag), aad, sizeof(aad), buf, sizeof(buf)); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(pt, m, sizeof(m)) == 0); ret: zpc_aes_gcm_free(&aes_gcm1); EXPECT_EQ(aes_gcm1, nullptr); zpc_aes_gcm_free(&aes_gcm2); EXPECT_EQ(aes_gcm2, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_gcm, encrypt) { struct zpc_aes_key *aes_key; struct zpc_aes_gcm *aes_gcm; const char *mkvp, *apqns[257]; u8 iv[12], aad[99], m[99], tag[12] = { 0, }, c[99]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); ret: zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_gcm, decrypt) { struct zpc_aes_key *aes_key; struct zpc_aes_gcm *aes_gcm; const char *mkvp, *apqns[257]; u8 iv[12], aad[99], m[99], tag[12] = { 0, }, c[99]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); ret: zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_gcm, pc) { struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_gcm *aes_gcm1, *aes_gcm2; const char *mkvp, *apqns[257]; u8 iv[12], aad[99], m[99], tag[12] = { 0, }, c[99], key[32], m_bak[99]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); memcpy(m_bak, m, 99); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm1); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key1, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_gcm_set_key(aes_gcm1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm1, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key2, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key2, size); if (rc) goto ret; } rc = zpc_aes_gcm_set_key(aes_gcm2, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm2, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm1, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm2, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 99) == 0); rc = zpc_aes_gcm_encrypt(aes_gcm2, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm1, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 99) == 0); rc = zpc_aes_gcm_encrypt(aes_gcm2, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); c[0] ^= 1; rc = zpc_aes_gcm_decrypt(aes_gcm1, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); rc = zpc_aes_gcm_encrypt(aes_gcm1, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); tag[0] ^= 1; rc = zpc_aes_gcm_decrypt(aes_gcm2, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); memcpy(m_bak, m, 99); /* Random protected key */ rc = zpc_aes_gcm_set_key(aes_gcm1, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_key(aes_gcm2, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(aes_key1, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_gcm_set_key(aes_gcm1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm1, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_key(aes_gcm2, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm2, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm1, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm2, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 99) == 0); rc = zpc_aes_gcm_encrypt(aes_gcm2, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm1, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 99) == 0); rc = zpc_aes_gcm_encrypt(aes_gcm2, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); c[0] ^= 1; rc = zpc_aes_gcm_decrypt(aes_gcm1, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); rc = zpc_aes_gcm_encrypt(aes_gcm1, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); tag[0] ^= 1; rc = zpc_aes_gcm_decrypt(aes_gcm2, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, ZPC_ERROR_TAGMISMATCH); ret: zpc_aes_gcm_free(&aes_gcm2); zpc_aes_gcm_free(&aes_gcm1); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); } TEST(aes_gcm, stream_inplace_kat1) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); size_t keylen, ivlen, msglen, ctlen, taglen, aadlen; unsigned char buf[4096], mac[16]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_gcm *aes_gcm; unsigned int flags; int type, rc; const char *keystr = "c4b03435b91fc52e09eff27e4dc3fb42"; const char *ivstr = "5046e7e08f0747e1efccb09e"; const char *aadstr = "75fc9078b488e9503dcb568c882c9eec24d80b04f0958c82aac8484f025c90434148db8e9bfe29c7e071b797457cb1695a5e5a6317b83690ba0538fb11e325ca"; const char *msgstr = "8e887b224e8b89c82e9a641cf579e6879e1111c7"; const char *ctstr = "b6786812574a254eb43b1cb1d1753564c6b520e9"; const char *tagstr = "ad8c09610d508f3d0f03cc523c0d5fcc"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 128, flags); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping stream_inplace_kat1 test. KATs cannot be performed with UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *aad = testlib_hexstr2buf(aadstr, &aadlen); ASSERT_NE(aad, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, NULL, NULL, 0, aad, 32, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, NULL, NULL, 0, aad + 32, aadlen - 31, NULL, 0); /* Works iff aadlen - 32 == 0 mod 16 */ EXPECT_EQ(rc, ZPC_ERROR_ARG6RANGE); rc = zpc_aes_gcm_encrypt(aes_gcm, NULL, NULL, 0, aad + 32, aadlen - 32, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, buf, NULL, 0, NULL, 0, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, buf + 16, mac, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, NULL, NULL, 0, aad, 32, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, buf, NULL, 0, aad + 32, aadlen - 32, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, buf + 16, NULL, 0, NULL, 0, buf + 16, msglen - 16); /* Works iff msglen - 16 == 0 mod 16 */ EXPECT_EQ(rc, ZPC_ERROR_ARG8RANGE); rc = zpc_aes_gcm_encrypt(aes_gcm, buf + 16, mac, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, NULL, NULL, 0, aad, 16, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, NULL, NULL, 0, aad + 16, aadlen - 15, NULL, 0); /* Works iff aadlen - 16 == 0 mod 16 */ EXPECT_EQ(rc, ZPC_ERROR_ARG6RANGE); rc = zpc_aes_gcm_decrypt(aes_gcm, buf, NULL, 0, aad + 16, aadlen - 16, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, buf + 16, tag, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, NULL, NULL, 0, aad, 16, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, NULL, NULL, 0, aad + 16, aadlen - 16, NULL, 0); /* Works iff aadlen - 16 == 0 mod 16 */ EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, buf, NULL, 0, NULL, 0, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, buf + 16, NULL, 0, NULL, 0, buf + 16, msglen - 16); /* Works iff msglen - 16 == 0 mod 16 */ EXPECT_EQ(rc, ZPC_ERROR_ARG8RANGE); rc = zpc_aes_gcm_decrypt(aes_gcm, buf + 16, tag, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(iv); free(aad); free(msg); free(ct); free(tag); } TEST(aes_gcm, stream_inplace_kat2) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); size_t keylen, ivlen, msglen, ctlen, taglen, aadlen; unsigned char buf[4096], mac[16]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_gcm *aes_gcm; unsigned int flags; int type, rc; const char *keystr = "deb62233559b57476602b5adac57c77f"; const char *ivstr = "d084547de55bbc15"; const char *aadstr = ""; const char *msgstr = "d8986df0241ed3297582c0c239c724cb"; const char *ctstr = "03e1a168a7e377a913879b296a1b5f9c"; const char *tagstr = "3290aa95af505a742f517fabcc9b2094"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 128, flags); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping stream_inplace_kat2 test. KATs cannot be performed with UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *aad = testlib_hexstr2buf(aadstr, &aadlen); ASSERT_EQ(aad, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, NULL, NULL, 0, aad, aadlen, NULL, 0); /* Works iff aadlen == 0 mod 16 */ EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, buf, NULL, 0, NULL, 0, buf, msglen); /* Works iff msglen == 0 mod 16 */ EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, NULL, mac, taglen, NULL, 0, NULL, 0); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, NULL, NULL, 0, aad, aadlen, NULL, 0); /* Works iff aadlen == 0 mod 16 */ EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, buf, NULL, 0, NULL, 0, buf, msglen); /* Works iff msglen == 0 mod 16 */ EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, NULL, tag, taglen, NULL, 0, NULL, 0); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(iv); free(aad); free(msg); free(ct); free(tag); } TEST(aes_gcm, wycheproof_kat) { int type; type = testlib_env_aes_key_type(); TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping wycheproof_kat test. KATs cannot be performed with UV secrets."); __run_json("wycheproof/src/wycheproof/testvectors/aes_gcm_test.json"); } TEST(aes_gcm, nist_kat) { int type; type = testlib_env_aes_key_type(); TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping nist_kat test. KATs cannot be performed with UV secrets."); __run_json("nist_aes_gcm.json"); } static void __run_json(const char *json) { const char *tv = json, *str; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_gcm *aes_gcm; unsigned int flags; u8 *key = NULL, *iv = NULL, *aad = NULL; u8 *pt = NULL, *pt_out = NULL, *ct = NULL, *ct_out = NULL; u8 *tag = NULL, *tag_out = NULL; int rc, tagsize = 0, ivsize = 0, keysize = 0; int valid = 0, ivlen0 = 0, deconly = 0; size_t aadlen, ptlen, ctlen, taglen, i, j, k, max; json_object *jkey, *jiv, *jtag, *jaad, *jmsg, *jct, *jresult, *jflags, *jtmp, *jtestgroups, *jfile, *jkeysize, *jivsize, *jtagsize, *jtests; json_bool b; int type; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); jfile = json_object_from_file(tv); ASSERT_NE(jfile, nullptr); b = json_object_object_get_ex(jfile, "testGroups", &jtestgroups); ASSERT_TRUE(b); for (i = 0; i < (size_t)json_object_array_length(jtestgroups); i++) { jtmp = json_object_array_get_idx(jtestgroups, i); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "keySize", &jkeysize); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "ivSize", &jivsize); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "tagSize", &jtagsize); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "tests", &jtests); ASSERT_TRUE(b); keysize = json_object_get_int(jkeysize); ivsize = json_object_get_int(jivsize); tagsize = json_object_get_int(jtagsize); rc = zpc_aes_key_set_size(aes_key, keysize); EXPECT_EQ(rc, 0); for (j = 0; j < (size_t)json_object_array_length(jtests); j++) { jtmp = json_object_array_get_idx(jtests, j); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "key", &jkey); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "iv", &jiv); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "tag", &jtag); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "aad", &jaad); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "msg", &jmsg); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "ct", &jct); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "flags", &jflags); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "result", &jresult); ASSERT_TRUE(b); str = json_object_get_string(jkey); ASSERT_NE(str, nullptr); key = testlib_hexstr2buf(str, NULL); ASSERT_NE(key, nullptr); str = json_object_get_string(jiv); ASSERT_NE(str, nullptr); iv = testlib_hexstr2buf(str, NULL); str = json_object_get_string(jtag); ASSERT_NE(str, nullptr); tag = testlib_hexstr2buf(str, &taglen); ASSERT_NE(tag, nullptr); tag_out = (unsigned char *)calloc(1, taglen); ASSERT_NE(tag_out, nullptr); str = json_object_get_string(jaad); ASSERT_NE(str, nullptr); aad = testlib_hexstr2buf(str, &aadlen); str = json_object_get_string(jmsg); ASSERT_NE(str, nullptr); pt = testlib_hexstr2buf(str, &ptlen); str = json_object_get_string(jct); ASSERT_NE(str, nullptr); ct = testlib_hexstr2buf(str, &ctlen); str = json_object_get_string(jresult); ASSERT_NE(str, nullptr); if (strcmp(str, "valid") == 0 || strcmp(str, "acceptable") == 0) valid = 1; else valid = 0; for (k = 0; k < (size_t)json_object_array_length(jflags); k++) { jtmp = json_object_array_get_idx(jflags, k); ASSERT_NE(jtmp, nullptr); str = json_object_get_string(jtmp); if (strcmp(str, "ZeroLengthIv") == 0) ivlen0 = 1; else ivlen0 = 0; str = json_object_get_string(jtmp); if (strcmp(str, "DecryptOnly") == 0) deconly = 1; else deconly = 0; } max = ptlen > ctlen ? ptlen : ctlen; pt_out = NULL; ct_out = NULL; if (max > 0) { pt_out = (unsigned char *)calloc(1, max); ASSERT_NE(pt_out, nullptr); ct_out = (unsigned char *)calloc(1, max); ASSERT_NE(ct_out, nullptr); } rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm, ivlen0 ? (unsigned char *)1 : iv, ivsize / 8); EXPECT_EQ(rc, ivlen0 ? ZPC_ERROR_IVSIZE : 0); if (!ivlen0 && !deconly) { rc = zpc_aes_gcm_encrypt(aes_gcm, ct_out, tag_out, tagsize / 8, aad, aadlen, pt, ptlen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(ct_out, ct, ctlen) == 0); if (valid) { EXPECT_TRUE(memcmp(tag_out, tag, tagsize / 8) == 0); } rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivsize / 8); EXPECT_EQ(rc, 0); } else if (!ivlen0) { rc = zpc_aes_gcm_decrypt(aes_gcm, pt_out, tag, tagsize / 8, aad, aadlen, ct, ctlen); EXPECT_EQ(rc, valid ? 0 : ZPC_ERROR_TAGMISMATCH); EXPECT_TRUE(memcmp(pt_out, pt, ptlen) == 0); } /* Unset key. */ rc = zpc_aes_gcm_set_key(aes_gcm, NULL); EXPECT_EQ(rc, 0); free(key); key = NULL; free(iv); iv = NULL; free(aad); aad = NULL; free(pt); pt = NULL; free(pt_out); pt_out = NULL; free(ct); ct = NULL; free(ct_out); ct_out = NULL; free(tag); tag = NULL; free(tag_out); tag_out = NULL; } } zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_gcm, rederive_protected_key1) { struct zpc_aes_key *aes_key1; struct zpc_aes_gcm *aes_gcm1, *aes_gcm2, *aes_gcm3; u8 iv[16], aad[99], m[99], tag[16], c[99]; /* use ivlen != 12 bytes such that it must be processed by kma */ int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); TESTLIB_AES_KERNEL_CAPS_CHECK(type); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm1); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm2); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm3); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_key(aes_gcm1, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_key(aes_gcm2, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_key(aes_gcm3, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); /* Random protected keys cannot be re-derived. */ rc = zpc_aes_key_set_mkvp(aes_key1, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); /* * This key obj has no type set. Therefore the generate will work also * for tests with ZPC_TEST_AES_KEY_TYPE = ZPC_AES_KEY_TYPE_PVSECRET. * The generated protected key has no dependency on any secure key or * pvsecret. */ rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_key(aes_gcm1, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm1, iv, sizeof(iv)); EXPECT_EQ(rc, 0); memset(aes_gcm1->param.protkey, 0, sizeof(aes_gcm1->param.protkey)); rc = zpc_aes_gcm_set_iv(aes_gcm1, iv, sizeof(iv)); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); rc = zpc_aes_gcm_set_key(aes_gcm2, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm2, iv, sizeof(iv)); EXPECT_EQ(rc, 0); memset(aes_gcm2->param.protkey, 0, sizeof(aes_gcm2->param.protkey)); rc = zpc_aes_gcm_encrypt(aes_gcm2, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); rc = zpc_aes_gcm_set_key(aes_gcm3, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(aes_gcm3, iv, sizeof(iv)); EXPECT_EQ(rc, 0); memset(aes_gcm3->param.protkey, 0, sizeof(aes_gcm3->param.protkey)); rc = zpc_aes_gcm_decrypt(aes_gcm3, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); rc = zpc_aes_gcm_set_key(aes_gcm1, aes_key1); EXPECT_EQ(rc, 0); memset(aes_gcm1->param.protkey, 0, sizeof(aes_gcm1->param.protkey)); rc = zpc_aes_gcm_set_iv(aes_gcm1, iv, sizeof(iv)); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); zpc_aes_gcm_free(&aes_gcm3); zpc_aes_gcm_free(&aes_gcm2); zpc_aes_gcm_free(&aes_gcm1); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_gcm3, nullptr); EXPECT_EQ(aes_gcm2, nullptr); EXPECT_EQ(aes_gcm1, nullptr); EXPECT_EQ(aes_key1, nullptr); } TEST(aes_gcm, rederive_protected_key2) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); size_t keylen, ivlen, msglen, ctlen, taglen, aadlen; unsigned char buf[4096], mac[16] = { 0, }, pvsec_ct[4096]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_gcm *aes_gcm; unsigned int flags; int type, rc; const char *keystr = "2034a82547276c83dd3212a813572bce"; const char *ivstr = "3254202d854734812398127a3d134421"; /* use ivlen != 12 bytes such that it must be processed by kma */ const char *aadstr = "1a0293d8f90219058902139013908190bc490890d3ff12a3"; const char *msgstr = "02efd2e5782312827ed5d230189a2a342b277ce048462193"; const char *ctstr = "64069c2d58690561f27ee199e6b479b6369eec688672bde9"; const char *tagstr = "9b7abadd6e69c1d9ec925786534f5075"; u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *aad = testlib_hexstr2buf(aadstr, &aadlen); ASSERT_NE(aad, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 128, flags); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, keylen * 8); if (rc) goto ret; } /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, 0); memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_encrypt(aes_gcm, NULL, NULL, 0, aad, 16, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, NULL, NULL, 0, aad + 16, aadlen - 15, NULL, 0); /* Works iff aadlen - 16 == 0 mod 16 */ EXPECT_EQ(rc, ZPC_ERROR_ARG6RANGE); rc = zpc_aes_gcm_encrypt(aes_gcm, buf, NULL, 0, aad + 16, aadlen - 16, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, buf + 16, mac, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); } else { memcpy(pvsec_ct, buf, ctlen); } /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, 0); memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_encrypt(aes_gcm, NULL, NULL, 0, aad, 16, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, buf, NULL, 0, aad + 16, aadlen - 16, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, buf + 16, NULL, 0, NULL, 0, buf + 16, msglen - 16); /* Works iff msglen - 16 == 0 mod 16 */ EXPECT_EQ(rc, ZPC_ERROR_ARG8RANGE); memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_encrypt(aes_gcm, buf + 16, mac, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); } else { EXPECT_TRUE(memcmp(buf, pvsec_ct, ctlen) == 0); // <- beim 2. encrypt kommt dasselbe raus } /* Decrypt */ if (type != ZPC_AES_KEY_TYPE_PVSECRET) { memcpy(buf, ct, ctlen); } else { memcpy(buf, pvsec_ct, ctlen); memcpy(tag, mac, taglen); } memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, NULL, NULL, 0, aad, 16, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, NULL, NULL, 0, aad + 16, aadlen - 15, NULL, 0); /* Works iff aadlen - 16 == 0 mod 16 */ EXPECT_EQ(rc, ZPC_ERROR_ARG6RANGE); memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_decrypt(aes_gcm, buf, NULL, 0, aad + 16, aadlen - 16, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, buf + 16, tag, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); /* Decrypt */ if (type != ZPC_AES_KEY_TYPE_PVSECRET) { memcpy(buf, ct, ctlen); } else { memcpy(buf, pvsec_ct, ctlen); memcpy(tag, mac, taglen); } memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_decrypt(aes_gcm, NULL, NULL, 0, aad, 16, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, buf, NULL, 0, aad + 16, aadlen - 16, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, buf + 16, NULL, 0, NULL, 0, buf + 16, msglen - 16); /* Works iff msglen - 16 == 0 mod 16 */ EXPECT_EQ(rc, ZPC_ERROR_ARG8RANGE); rc = zpc_aes_gcm_decrypt(aes_gcm, buf + 16, tag, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); ret: zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(iv); free(aad); free(msg); free(ct); free(tag); } TEST(aes_gcm, reencipher) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); size_t keylen, ivlen, msglen, ctlen, taglen, aadlen; unsigned char buf[4096], mac[16]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; struct zpc_aes_gcm *aes_gcm; unsigned int flags; int type, rc; const char *keystr = "2034a82547276c83dd3212a813572bce"; const char *ivstr = "3254202d854734812398127a3d134421"; /* use ivlen != 12 bytes such that it must be processed by kma */ const char *aadstr = "1a0293d8f90219058902139013908190bc490890d3ff12a3"; const char *msgstr = "02efd2e5782312827ed5d230189a2a342b277ce048462193"; const char *ctstr = "64069c2d58690561f27ee199e6b479b6369eec688672bde9"; const char *tagstr = "9b7abadd6e69c1d9ec925786534f5075"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); TESTLIB_AES_NEW_MK_CHECK(type, mkvp, apqns); if (type == ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping reencipher test. Not applicable for UV secrets."); u8 *key = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key, nullptr); u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *aad = testlib_hexstr2buf(aadstr, &aadlen); ASSERT_NE(aad, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&aes_gcm); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_reencipher(aes_key, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key->cur, 0, sizeof(aes_key->cur)); /* destroy current secure key */ /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_encrypt(aes_gcm, NULL, NULL, 0, aad, 16, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, NULL, NULL, 0, aad + 16, aadlen - 15, NULL, 0); /* Works iff aadlen - 16 == 0 mod 16 */ EXPECT_EQ(rc, ZPC_ERROR_ARG6RANGE); rc = zpc_aes_gcm_encrypt(aes_gcm, buf, NULL, 0, aad + 16, aadlen - 16, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, buf + 16, mac, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_encrypt(aes_gcm, NULL, NULL, 0, aad, 16, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, buf, NULL, 0, aad + 16, aadlen - 16, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, buf + 16, NULL, 0, NULL, 0, buf + 16, msglen - 16); /* Works iff msglen - 16 == 0 mod 16 */ EXPECT_EQ(rc, ZPC_ERROR_ARG8RANGE); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_encrypt(aes_gcm, buf + 16, mac, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, NULL, NULL, 0, aad, 16, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, NULL, NULL, 0, aad + 16, aadlen - 15, NULL, 0); /* Works iff aadlen - 16 == 0 mod 16 */ EXPECT_EQ(rc, ZPC_ERROR_ARG6RANGE); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_decrypt(aes_gcm, buf, NULL, 0, aad + 16, aadlen - 16, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, buf + 16, tag, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_decrypt(aes_gcm, NULL, NULL, 0, aad, 16, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, buf, NULL, 0, aad + 16, aadlen - 16, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, buf + 16, NULL, 0, NULL, 0, buf + 16, msglen - 16); /* Works iff msglen - 16 == 0 mod 16 */ EXPECT_EQ(rc, ZPC_ERROR_ARG8RANGE); rc = zpc_aes_gcm_decrypt(aes_gcm, buf + 16, tag, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); free(iv); free(aad); free(msg); free(ct); free(tag); } /* * This test assumes that the tester manually added the clear AES key with * given size to the pvsecret list file, for example: * * 5 AES-128-KEY: * 0x8ace2a9bc6f28ae3 ... <- secret ID * 0xbe0274e3f3b36 ... <- clear AES key * ... * * The test creates one pvsecret-type key and one CCA or EP11 type * single AES key with the given clear key material to compare results. * The specified APQN(s) decide if the single keys are CCA or EP11. */ TEST(aes_gcm, pvsecret_kat) { struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_gcm *ctx1, *ctx2; u8 iv[12], aad[99], m[99], tag[12] = { 0, }, c[99], m_bak[99], c_bak[99]; const char *mkvp, *apqns[257]; unsigned int flags; int type, type2, rc, size; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); if (type != ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping pvsecret_kat test. Only applicable for UV secrets."); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); TESTLIB_EC_NEW_MK_CHECK(type, mkvp, apqns); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&ctx1); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_alloc(&ctx2); EXPECT_EQ(rc, 0); /* * key1 is created from pvsecret. */ rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; rc = zpc_aes_gcm_set_key(ctx1, aes_key1); EXPECT_EQ(rc, 0); /* * key2 is a normal AES key and contains clear key material from list * file. We first try to create a CCA type key with the given APQN(s), * if this fails we retry with EP11. */ type2 = ZPC_AES_KEY_TYPE_CCA_DATA; while (1) { rc = zpc_aes_key_set_type(aes_key2, type2); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = testlib_set_aes_key_from_file(aes_key2, type2, size); if (rc == ZPC_ERROR_IOCTLCLR2SECK2) { type2 = ZPC_AES_KEY_TYPE_EP11; continue; } if (rc) goto ret; else break; } rc = zpc_aes_gcm_set_key(ctx2, aes_key2); EXPECT_EQ(rc, 0); /* Now encrypt with both keys and compare result */ rc = zpc_aes_gcm_set_iv(ctx1, iv, 12); EXPECT_EQ(rc, 0); memcpy(m_bak, m, 99); rc = zpc_aes_gcm_encrypt(ctx1, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); memcpy(c_bak, c, 99); rc = zpc_aes_gcm_set_iv(ctx2, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(ctx2, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(c, c_bak, 99) == 0); /* Now encrypt with key1 and decrypt with key2 */ rc = zpc_aes_gcm_set_iv(ctx1, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(ctx1, c, tag, 12, aad, 99, m, 99); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_iv(ctx2, iv, 12); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(ctx2, m, tag, 12, aad, 99, c, 99); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 99) == 0); ret: zpc_aes_gcm_free(&ctx1); EXPECT_EQ(ctx1, nullptr); zpc_aes_gcm_free(&ctx2); EXPECT_EQ(ctx2, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); } static void __task(struct zpc_aes_key *aes_key) { struct zpc_aes_gcm *aes_gcm; unsigned char buf[4096], mac[16] = { 0,}; size_t ivlen, msglen, ctlen, taglen, aadlen; int rc, i; const char *ivstr = "3254202d854734812398127a3d134421"; /* use ivlen != 12 bytes such that it must be processed by kma */ const char *aadstr = "1a0293d8f90219058902139013908190bc490890d3ff12a3"; const char *msgstr = "02efd2e5782312827ed5d230189a2a342b277ce048462193"; const char *ctstr = "64069c2d58690561f27ee199e6b479b6369eec688672bde9"; const char *tagstr = "9b7abadd6e69c1d9ec925786534f5075"; u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *aad = testlib_hexstr2buf(aadstr, &aadlen); ASSERT_NE(aad, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); u8 *tag = testlib_hexstr2buf(tagstr, &taglen); ASSERT_NE(tag, nullptr); rc = zpc_aes_gcm_alloc(&aes_gcm); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_set_key(aes_gcm, aes_key); EXPECT_EQ(rc, 0); for (i = 0; i < 1000; i++) { /* Encrypt */ memcpy(buf, msg, msglen); memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_encrypt(aes_gcm, NULL, NULL, 0, aad, 16, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, buf, NULL, 0, aad + 16, aadlen - 16, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_encrypt(aes_gcm, buf + 16, mac, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); if (aes_key->type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); EXPECT_TRUE(memcmp(mac, tag, taglen) == 0); } /* Decrypt */ if (aes_key->type != ZPC_AES_KEY_TYPE_PVSECRET) { memcpy(buf, ct, ctlen); } else { memcpy(tag, mac, taglen); } rc = zpc_aes_gcm_set_iv(aes_gcm, iv, ivlen); EXPECT_EQ(rc, 0); memset(aes_gcm->param.protkey, 0, sizeof(aes_gcm->param.protkey)); /* force WKaVP mismatch */ rc = zpc_aes_gcm_decrypt(aes_gcm, NULL, NULL, 0, aad, 16, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, buf, NULL, 0, aad + 16, aadlen - 16, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_gcm_decrypt(aes_gcm, buf + 16, tag, taglen, NULL, 0, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); } zpc_aes_gcm_free(&aes_gcm); EXPECT_EQ(aes_gcm, nullptr); free(iv); free(aad); free(msg); free(ct); free(tag); } TEST(aes_gcm, threads) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_GCM_HW_CAPS_CHECK(); size_t keylen; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key; unsigned int flags; int type, rc, i; std::thread *t[500]; const char *keystr = "2034a82547276c83dd3212a813572bce"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 128, flags); TESTLIB_AES_NEW_MK_CHECK(type, mkvp, apqns); u8 *key = testlib_hexstr2buf(keystr, &keylen); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, keylen * 8); if (rc) goto ret; } for (i = 0; i < 500; i++) { t[i] = new std::thread(__task, aes_key); } /* Do something with key object while threads are working with it. */ if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_reencipher(aes_key, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key->cur, 0, sizeof(aes_key->cur)); /* destroy current secure key */ } for (i = 0; i < 500; i++) { memset(&aes_key->prot, 0, sizeof(aes_key->prot)); /* destroy cached protected key */ usleep(1); } for (i = 0; i < 500; i++) { t[i]->join(); delete t[i]; } ret: zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); free(key); } libzpc-1.3.0/test/t_aes_key.cc000066400000000000000000000500771475140344100162430ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "testlib.h" #include "gtest/gtest.h" #include "zpc/aes_key.h" #include "zpc/error.h" TEST(aes_key, alloc) { struct zpc_aes_key *aes_key; int rc; TESTLIB_ENV_AES_KEY_CHECK(); rc = zpc_aes_key_alloc(NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); aes_key = NULL; rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); aes_key = (struct zpc_aes_key *)&aes_key; rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_key, free) { struct zpc_aes_key *aes_key; int rc; TESTLIB_ENV_AES_KEY_CHECK(); zpc_aes_key_free(NULL); aes_key = NULL; zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_key, set_keysize) { struct zpc_aes_key *aes_key; int rc; TESTLIB_ENV_AES_KEY_CHECK(); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(NULL, -1); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_size(NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_size(NULL, 1); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_size(NULL, 128); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_size(NULL, 192); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_size(NULL, 256); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_size(aes_key, -1); EXPECT_EQ(rc, ZPC_ERROR_KEYSIZE); rc = zpc_aes_key_set_size(aes_key, 0); EXPECT_EQ(rc, ZPC_ERROR_KEYSIZE); rc = zpc_aes_key_set_size(aes_key, 1); EXPECT_EQ(rc, ZPC_ERROR_KEYSIZE); rc = zpc_aes_key_set_size(aes_key, 128); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, 192); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, 256); EXPECT_EQ(rc, 0); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_key, set_type) { struct zpc_aes_key *aes_key; int rc; TESTLIB_ENV_AES_KEY_CHECK(); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(NULL, -1); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_type(NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_type(NULL, ZPC_AES_KEY_TYPE_CCA_DATA); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_type(NULL, ZPC_AES_KEY_TYPE_CCA_CIPHER); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_type(NULL, ZPC_AES_KEY_TYPE_EP11); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_type(NULL, 4); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_type(aes_key, -1); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPE); rc = zpc_aes_key_set_type(aes_key, 0); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPE); rc = zpc_aes_key_set_type(aes_key, ZPC_AES_KEY_TYPE_CCA_DATA); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, ZPC_AES_KEY_TYPE_CCA_CIPHER); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, ZPC_AES_KEY_TYPE_EP11); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, ZPC_AES_KEY_TYPE_PVSECRET); EXPECT_TRUE(rc == 0 || rc == ZPC_ERROR_UV_PVSECRETS_NOT_AVAILABLE); rc = zpc_aes_key_set_type(aes_key, 5); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPE); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_key, set_flags) { struct zpc_aes_key *aes_key; int rc; TESTLIB_ENV_AES_KEY_CHECK(); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_flags(aes_key, -1); EXPECT_EQ(rc, 0); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_key, set_mkvp) { struct zpc_aes_key *aes_key; const char *mkvp; unsigned int flags; int rc, type; TESTLIB_ENV_AES_KEY_CHECK(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_mkvp(NULL, mkvp); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_mkvp(aes_key, NULL); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(aes_key, mkvp); if (mkvp != NULL) EXPECT_EQ(rc, ZPC_ERROR_KEYTYPENOTSET); else EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_TRUE(rc == 0 || rc == ZPC_ERROR_UV_PVSECRETS_NOT_AVAILABLE); rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_key, set_apqns) { struct zpc_aes_key *aes_key; const char *apqns[] = {"01.0037", "\n01.0037\t ", NULL}; /* apqn example */ int rc; TESTLIB_ENV_AES_KEY_CHECK(); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_apqns(NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_apqns(NULL, apqns); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_set_apqns(aes_key, NULL); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_key, import_clear_1) { struct zpc_aes_key *aes_key; const u8 key[32] = {0}; const char *apqns[257]; unsigned int flags; int rc, type, size; const char *mkvp; TESTLIB_ENV_AES_KEY_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_AES_SW_CAPS_CHECK(type); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping import_clear_1 test. UV secrets cannot be imported in clear form."); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_import_clear(NULL, key); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_import_clear(aes_key, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG2NULL); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, ZPC_ERROR_APQNSNOTSET); if (mkvp == NULL) { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, ZPC_ERROR_KEYSIZENOTSET); } rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (mkvp == NULL) { rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPENOTSET); } rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_import_clear(aes_key, key); EXPECT_EQ(rc, 0); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_key, import_clear_2) { struct zpc_aes_key *aes_key; u8 clearkey[32]; const char *apqns[257]; unsigned int flags; int rc, size, type; const char *mkvp; TESTLIB_ENV_AES_KEY_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags= testlib_env_aes_key_type(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_AES_SW_CAPS_CHECK(type); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping import_clear_2 test. UV secrets cannot be imported in clear form."); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); /* mkvp */ rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_import_clear(aes_key, clearkey); EXPECT_EQ(rc, 0); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_key, generate_1) { struct zpc_aes_key *aes_key; unsigned int flags; const char *apqns[257]; int rc, size, type; const char *mkvp; TESTLIB_ENV_AES_KEY_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags= testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_AES_SW_CAPS_CHECK(type); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping generate_1 test. UV secrets cannot be generated."); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_generate(NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, ZPC_ERROR_KEYSIZENOTSET); if (mkvp == NULL) { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, ZPC_ERROR_KEYSIZENOTSET); } rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); if (mkvp == NULL) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPENOTSET); } rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_key, generate_2) { struct zpc_aes_key *aes_key; unsigned int flags; const char *apqns[257]; int rc, size, type; const char *mkvp; TESTLIB_ENV_AES_KEY_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags= testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_AES_SW_CAPS_CHECK(type); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping generate_2 test. UV secrets cannot be generated."); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_key, reencipher) { struct zpc_aes_key *aes_key; unsigned int flags; const char *apqns[257]; int rc, size, type; const char *mkvp; TESTLIB_ENV_AES_KEY_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags= testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_AES_NEW_MK_CHECK(type, mkvp, apqns); if (type == ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping reencipher test. Not applicable for UV secrets."); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_reencipher(aes_key, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_key, export) { struct zpc_aes_key *aes_key; u8 buf[10000]; unsigned int flags; const char *apqns[257]; int rc, size, type; size_t buflen; const char *mkvp; TESTLIB_ENV_AES_KEY_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags= testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_AES_SW_CAPS_CHECK(type); rc = zpc_aes_key_export(NULL, NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_export(aes_key, NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG3NULL); rc = zpc_aes_key_export(aes_key, NULL, &buflen); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } buflen = 0; rc = zpc_aes_key_export(aes_key, buf, &buflen); EXPECT_EQ(rc, ZPC_ERROR_SMALLOUTBUF); rc = zpc_aes_key_export(aes_key, NULL, &buflen); EXPECT_EQ(rc, 0); EXPECT_GT(buflen, 0UL); rc = zpc_aes_key_export(aes_key, buf, &buflen); EXPECT_EQ(rc, 0); ret: zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); } TEST(aes_key, import) { struct zpc_aes_key *aes_key, *aes_key2; u8 buf[10000], buf2[10000]; unsigned int flags; const char *apqns[257]; int rc, size, type; size_t buflen = sizeof(buf); size_t buf2len = sizeof(buf2); const char *mkvp; TESTLIB_ENV_AES_KEY_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags= testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import(NULL, NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_key_import(aes_key, NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG2NULL); rc = zpc_aes_key_import(aes_key, buf, 63); EXPECT_EQ(rc, ZPC_ERROR_ARG3RANGE); rc = zpc_aes_key_import(aes_key, buf, 630); EXPECT_EQ(rc, ZPC_ERROR_ARG3RANGE); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import(aes_key, buf, 64); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPENOTSET); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key, size); if (rc) goto ret; } rc = zpc_aes_key_export(aes_key, buf, &buflen); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import(aes_key2, buf, buflen); EXPECT_EQ(rc, 0); rc = zpc_aes_key_export(aes_key2, buf2, &buf2len); EXPECT_EQ(rc, 0); EXPECT_EQ(buf2len, buflen); EXPECT_TRUE(memcmp(buf2, buf, buflen) == 0); ret: zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); } TEST(aes_key, import_old) { struct zpc_aes_key *aes_key, *aes_key2; u8 buf[1000], buf2[1000], buf3[1000]; u8 session[32]; unsigned int flags, key_had_a_session = 0; const char *apqns[257]; int rc, size, type; size_t buflen = sizeof(buf); size_t buf2len = sizeof(buf2); size_t buf3len = sizeof(buf3); const char *mkvp; struct ep11kblob_header { u8 type; /* always 0x00 */ u8 hver; /* header version, currently needs to be 0x00 */ u16 len; /* total length in bytes (including this header) */ u8 version; /* PKEY_TYPE_EP11_AES or PKEY_TYPE_EP11_ECC */ u8 res0; /* unused */ u16 bitlen; /* clear key bit len, 0 for unknown */ u8 res1[8]; /* unused */ } __attribute__((packed)); struct ep11kblob_header *ep11hdr; TESTLIB_ENV_AES_KEY_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags= testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); if (type != ZPC_AES_KEY_TYPE_EP11) GTEST_SKIP_("Skipping old style import test. Only supported for EP11 type keys."); rc = zpc_aes_key_alloc(&aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key, type); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key, mkvp); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key, apqns); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key, flags); EXPECT_EQ(rc, 0); /* Generate: will result in a TOKVER_EP11_AES_WITH_HEADER */ rc = zpc_aes_key_generate(aes_key); EXPECT_EQ(rc, 0); rc = zpc_aes_key_export(aes_key, buf, &buflen); EXPECT_EQ(rc, 0); /* Check if the key contains a session id. In this case let's save the * session before converting the blob into an "old style" key. */ memset(session, 0, 32); ep11hdr = (struct ep11kblob_header *)buf; if (ep11hdr->version == 0x06 && memcmp(buf + sizeof(struct ep11kblob_header), session, 32) != 0) { memcpy(session, buf + sizeof(struct ep11kblob_header), 32); key_had_a_session = 1; } /* Convert blob into an "old style" TOKVER_EP11_AES without header. For * backward compatibility such keys are still accepted, but internally * converted into "new style" keys with header. */ memset(buf3, 0, sizeof(buf3)); buf3len = buflen - sizeof(struct ep11kblob_header); memcpy(buf3, buf + sizeof(struct ep11kblob_header), buf3len); memset(buf3, 0, 32); ep11hdr = (struct ep11kblob_header *)buf3; ep11hdr->version = 0x03; /* TOKVER_EP11_AES */ ep11hdr->len = buf3len; ep11hdr->bitlen = size; /* Import "old style" key */ rc = zpc_aes_key_import(aes_key2, buf3, buf3len); EXPECT_EQ(rc, 0); /* Export will result in a converted TOKVER_EP11_AES_WITH_HEADER and * should be identical to the first export. */ rc = zpc_aes_key_export(aes_key2, buf2, &buf2len); EXPECT_EQ(rc, 0); /* If the original key had a session id, restore it now */ if (key_had_a_session) memcpy(buf2 + sizeof(struct ep11kblob_header), session, 32); EXPECT_EQ(buf2len, buflen); EXPECT_TRUE(memcmp(buf2, buf, buflen) == 0); /* Now try a TOKVER_EP11_AES key that has an overlayed header, but the * remaining 16 bytes of the session id field are not zero. This key * is considered as corrupted. */ memset(buf3 + 16, 0x5c, sizeof(struct ep11kblob_header)); rc = zpc_aes_key_import(aes_key2, buf3, buf3len); EXPECT_EQ(rc, ZPC_ERROR_AES_NO_EP11_SECUREKEY_TOKEN); /* Now try a TOKVER_EP11_AES key that is session-bound, i.e. * has a 32 byte session id instead of an overlayed header. This key * cannot be recognized, because of missing header information. */ memset(buf3, 0x5c, 32); /* fake a 32-byte session id */ rc = zpc_aes_key_import(aes_key2, buf3, buf3len); EXPECT_EQ(rc, ZPC_ERROR_AES_NO_EP11_SECUREKEY_TOKEN); zpc_aes_key_free(&aes_key); EXPECT_EQ(aes_key, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); } libzpc-1.3.0/test/t_aes_xts.cc000066400000000000000000001577461475140344100163040ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "testlib.h" #include "gtest/gtest.h" #include "zpc/aes_xts.h" #include "zpc/error.h" #include "aes_key_local.h" /* de-opaquify struct zpc_aes_key */ #include "aes_xts_local.h" /* de-opaquify struct zpc_aes_xts */ #include #include #include #include static void __run_json(const char *json); TEST(aes_xts, alloc) { struct zpc_aes_xts *aes_xts; int rc; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); rc = zpc_aes_xts_alloc(NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); aes_xts = NULL; rc = zpc_aes_xts_alloc(&aes_xts); EXPECT_EQ(rc, 0); zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); aes_xts = (struct zpc_aes_xts *)&aes_xts; rc = zpc_aes_xts_alloc(&aes_xts); EXPECT_EQ(rc, 0); zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); } TEST(aes_xts, free) { struct zpc_aes_xts *aes_xts; int rc; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); zpc_aes_xts_free(NULL); aes_xts = NULL; zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); rc = zpc_aes_xts_alloc(&aes_xts); EXPECT_EQ(rc, 0); zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); } TEST(aes_xts, set_key) { struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_xts *aes_xts; u8 clearkey1[32], clearkey2[32], iv[16]; unsigned int flags = 0; const char *mkvp, *apqns[257]; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_AES_XTS_KEY_SIZE_CHECK(size); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key1, clearkey1); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key2, clearkey2); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key2, size); if (rc) goto ret; } rc = zpc_aes_xts_set_key(NULL, NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_xts_set_key(NULL, aes_key1, aes_key2); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_xts_set_key(aes_xts, NULL, NULL); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts, aes_key2, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts, aes_key1, NULL); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts, NULL, aes_key1); EXPECT_EQ(rc, 0); ret: zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); } TEST(aes_xts, set_iv) { struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_xts *aes_xts; const char *mkvp, *apqns[257]; u8 iv[16]; int rc, size, type; unsigned int flags; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_AES_XTS_KEY_SIZE_CHECK(size); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_xts_set_iv(NULL, iv); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_aes_xts_set_iv(aes_xts, NULL); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key2); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key2, size); if (rc) goto ret; } rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, ZPC_ERROR_KEYNOTSET); rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); ret: zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); } TEST(aes_xts, encrypt) { struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_xts *aes_xts; const char *mkvp, *apqns[257]; u8 iv[16], m[64], c[64]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_AES_XTS_KEY_SIZE_CHECK(size); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key2); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key2, size); if (rc) goto ret; } rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(aes_xts, c, m, 64); EXPECT_EQ(rc, 0); ret: zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); } TEST(aes_xts, decrypt) { struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_xts *aes_xts; const char *mkvp, *apqns[257]; u8 iv[16], m[64], c[64]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_AES_XTS_KEY_SIZE_CHECK(size); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key2); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key2, size); if (rc) goto ret; } rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts, m, c, 64); EXPECT_EQ(rc, 0); ret: zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); } TEST(aes_xts, pc) { struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_xts *aes_xts1, *aes_xts2; const char *mkvp, *apqns[257]; u8 iv[16], m[96], c[96], key[32], m_bak[96]; unsigned int flags; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_AES_XTS_KEY_SIZE_CHECK(size); memcpy(m_bak, m, 96); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts1); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key1, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; } rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key2, key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key2, size); if (rc) goto ret; } rc = zpc_aes_xts_set_key(aes_xts1, aes_key1, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts1, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts2, aes_key1, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts2, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(aes_xts1, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts2, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); rc = zpc_aes_xts_encrypt(aes_xts2, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts1, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); rc = zpc_aes_xts_encrypt(aes_xts2, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts1, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); rc = zpc_aes_xts_encrypt(aes_xts1, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts2, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); /* Random protected key */ rc = zpc_aes_xts_set_key(aes_xts1, NULL, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts2, NULL, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(aes_key1, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(aes_key2, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_generate(aes_key2); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); rc += testlib_set_aes_key_from_pvsecret(aes_key2, size); if (rc) goto ret; } rc = zpc_aes_xts_set_key(aes_xts1, aes_key1, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts1, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts2, aes_key1, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts2, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(aes_xts1, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts2, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); rc = zpc_aes_xts_encrypt(aes_xts2, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts1, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); rc = zpc_aes_xts_encrypt(aes_xts2, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts1, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); rc = zpc_aes_xts_encrypt(aes_xts1, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts2, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); ret: zpc_aes_xts_free(&aes_xts2); zpc_aes_xts_free(&aes_xts1); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); } TEST(aes_xts, stream_inplace_kat1) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); size_t keylen, msglen, ctlen, ivlen; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_xts *aes_xts; unsigned int flags; int type, rc; const char *keystr = "88dfd7c83cb121968feb417520555b36c0f63b662570eac12ea96cbe188ad5b1a44db23ac6470316cba0041cadf248f6d9a7713f454e663f3e3987585cebbf96"; const char *ivstr = "0ee84632b838dd528f1d96c76439805c"; const char *msgstr = "ec36551c70efcdf85de7a39988978263ad261e83996dad219a0058e02187384f2d0754ff9cfa000bec448fafd2cfa738"; const char *ctstr = "a55d533c9c5885562b92d4582ea69db8e2ba9c0b967a9f0167700b043525a47bafe7d630774eaf4a1dc9fbcf94a1fda4"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping stream_inplace_kat1 test. KATs cannot be performed with UV secrets."); u8 *key1 = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key1, nullptr); keylen /= 2; u8 *key2 = key1 + keylen; u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key1, key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key2, key2); EXPECT_EQ(rc, 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(aes_xts, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(aes_xts, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(aes_xts, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(aes_xts, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts, buf, buf, 16); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); free(key1); free(iv); free(msg); free(ct); } TEST(aes_xts, stream_inplace_kat2) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); size_t keylen, ivlen, msglen, ctlen; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_xts *aes_xts; unsigned int flags; int type, rc; const char *keystr = "394c97881abd989d29c703e48a72b397a7acf51b59649eeea9b33274d8541df4"; const char *ivstr = "4b15c684a152d485fe9937d39b168c29"; const char *msgstr = "2f3b9dcfbae729583b1d1ffdd16bb6fe2757329435662a78f0"; const char *ctstr = "f3473802e38a3ffef4d4fb8e6aa266ebde553a64528a06463e"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 128, flags); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping stream_inplace_kat2 test. KATs cannot be performed with UV secrets."); u8 *key1 = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key1, nullptr); keylen /= 2; u8 *key2 = key1 + keylen; u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key1, key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key2, key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(aes_xts, buf, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts, buf, buf, ctlen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); free(key1); free(iv); free(msg); free(ct); } TEST(aes_xts, stream_inplace_kat3) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); size_t keylen, ivlen, msglen, ctlen; unsigned char buf[4096], iv2[16]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_xts *aes_xts1, *aes_xts2; unsigned int flags; int type, rc, size, i; const char *keystr[] = { "63f36e9c397c6523c99f1644ecb1a5d9bc0f2f55fbe324444c390fae752ad4d7", "88dfd7c83cb121968feb417520555b36c0f63b662570eac12ea96cbe188ad5b1a44db23ac6470316cba0041cadf248f6d9a7713f454e663f3e3987585cebbf96", }; const char *ivstr[] = { "cdb1bd3486f353cc160a840beadf0329", "0ee84632b838dd528f1d96c76439805c", }; const char *msgstr[] = { "9a0149888bf76160a81428bc9140eccd26ed18368e24d49b9cc512929a88ad1e66c763f4f56b63bb9dd9508c5d4df465", "ec36551c70efcdf85de7a39988978263ad261e83996dad219a0058e02187384f2d0754ff9cfa000bec448fafd2cfa738", }; const char *ctstr[] = { "0eeef28ca159b805f5c215610551678ab772f279374fb140ab550768db42cf6cb73637641934195ffc08cf5a9188b82b", "a55d533c9c5885562b92d4582ea69db8e2ba9c0b967a9f0167700b043525a47bafe7d630774eaf4a1dc9fbcf94a1fda4", }; size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); TESTLIB_AES_XTS_KEY_SIZE_CHECK(size); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping stream_inplace_kat3 test. KATs cannot be performed with UV secrets."); i = size == 128 ? 0 : 1; u8 *key1 = testlib_hexstr2buf(keystr[i], &keylen); ASSERT_NE(key1, nullptr); keylen /= 2; u8 *key2 = key1 + keylen; u8 *iv = testlib_hexstr2buf(ivstr[i], &ivlen); ASSERT_NE(iv, nullptr); u8 *msg = testlib_hexstr2buf(msgstr[i], &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr[i], &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts1); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key1, key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key2, key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts1, aes_key1, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts2, aes_key1, aes_key2); EXPECT_EQ(rc, 0); /* Encrypt first chunk with first ctx */ memcpy(buf, msg, msglen); rc = zpc_aes_xts_set_iv(aes_xts1, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(aes_xts1, buf, buf, 16); EXPECT_EQ(rc, 0); /* Get intermediate iv from first ctx */ rc = zpc_aes_xts_get_intermediate_iv(aes_xts1, iv2); EXPECT_EQ(rc, 0); /* Encrypt a 2nd chunk with 2nd ctx */ rc = zpc_aes_xts_set_iv(aes_xts2, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_intermediate_iv(aes_xts2, iv2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(aes_xts2, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, msglen) == 0); /* Decrypt first chunk with first ctx */ memcpy(buf, ct, ctlen); rc = zpc_aes_xts_set_iv(aes_xts1, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts1, buf, buf, 16); EXPECT_EQ(rc, 0); /* Get intermediate iv from first ctx */ rc = zpc_aes_xts_get_intermediate_iv(aes_xts1, iv2); EXPECT_EQ(rc, 0); /* Decrypt remaining chunk with 2nd ctx */ rc = zpc_aes_xts_set_iv(aes_xts2, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_intermediate_iv(aes_xts2, iv2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts2, buf + 16, buf + 16, msglen - 16); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_xts_free(&aes_xts1); EXPECT_EQ(aes_xts1, nullptr); zpc_aes_xts_free(&aes_xts2); EXPECT_EQ(aes_xts2, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); free(key1); free(iv); free(msg); free(ct); } TEST(aes_xts, nist_kat) { int type; type = testlib_env_aes_key_type(); TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); if (type == ZPC_AES_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping nist_kat test. KATs cannot be performed with UV secrets."); __run_json("nist_aes_xts.json"); } static void __run_json(const char *json) { const char *tv = json, *str; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_xts *aes_xts; unsigned int flags; u8 *key1 = NULL, *key2 = NULL, *iv = NULL; u8 *pt = NULL, *pt_out = NULL, *ct = NULL, *ct_out = NULL; int rc, keysize = 0; size_t ptlen, ctlen, i, j, max; json_object *jkey, *jiv, *jmsg, *jct, *jtmp, *jtestgroups, *jfile, *jkeysize, *jtests; json_bool b; int type; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 256, flags); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); jfile = json_object_from_file(tv); ASSERT_NE(jfile, nullptr); b = json_object_object_get_ex(jfile, "testGroups", &jtestgroups); ASSERT_TRUE(b); for (i = 0; i < (size_t)json_object_array_length(jtestgroups); i++) { jtmp = json_object_array_get_idx(jtestgroups, i); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "keySize", &jkeysize); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "tests", &jtests); ASSERT_TRUE(b); keysize = json_object_get_int(jkeysize); rc = zpc_aes_key_set_size(aes_key1, keysize); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, keysize); EXPECT_EQ(rc, 0); for (j = 0; j < (size_t)json_object_array_length(jtests); j++) { jtmp = json_object_array_get_idx(jtests, j); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "key", &jkey); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "iv", &jiv); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "msg", &jmsg); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "ct", &jct); ASSERT_TRUE(b); str = json_object_get_string(jkey); ASSERT_NE(str, nullptr); key1 = testlib_hexstr2buf(str, NULL); ASSERT_NE(key1, nullptr); key2 = key1 + (keysize / 8); str = json_object_get_string(jiv); ASSERT_NE(str, nullptr); iv = testlib_hexstr2buf(str, NULL); str = json_object_get_string(jmsg); ASSERT_NE(str, nullptr); pt = testlib_hexstr2buf(str, &ptlen); str = json_object_get_string(jct); ASSERT_NE(str, nullptr); ct = testlib_hexstr2buf(str, &ctlen); max = ptlen > ctlen ? ptlen : ctlen; pt_out = NULL; ct_out = NULL; if (max > 0) { pt_out = (unsigned char *)calloc(1, max); ASSERT_NE(pt_out, nullptr); ct_out = (unsigned char *)calloc(1, max); ASSERT_NE(ct_out, nullptr); } rc = zpc_aes_key_import_clear(aes_key1, key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key2, key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(aes_xts, ct_out, pt, ptlen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(ct_out, ct, ctlen) == 0); rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(aes_xts, pt_out, ct, ctlen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(pt_out, pt, ptlen) == 0); /* Unset key. */ rc = zpc_aes_xts_set_key(aes_xts, NULL, NULL); EXPECT_EQ(rc, 0); free(key1); key1 = NULL; free(iv); iv = NULL; free(pt); pt = NULL; free(pt_out); pt_out = NULL; free(ct); ct = NULL; free(ct_out); ct_out = NULL; } } zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); } TEST(aes_xts, rederive_protected_key1) { struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_xts *aes_xts1, *aes_xts2, *aes_xts3; u8 iv[16], m[96], c[96]; int rc, size, type; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_XTS_KEY_SIZE_CHECK(size); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts1); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts3); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts1, NULL, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts2, NULL, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts3, NULL, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); /* Random protected keys cannot be re-derived. */ rc = zpc_aes_key_set_mkvp(aes_key1, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_generate(aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(aes_key2, NULL); /* Unset apqns. */ EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); /* * This key obj has no type set. Therefore the generate will work also * for tests with ZPC_TEST_AES_KEY_TYPE = ZPC_AES_KEY_TYPE_PVSECRET. * The generated protected key has no dependency on any secure key or * pvsecret. */ rc = zpc_aes_key_generate(aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts1, aes_key1, aes_key2); EXPECT_EQ(rc, 0); memset(aes_xts1->param_pcc, 0, AES_XTS_PROTKEYLEN(aes_xts1->aes_key2->keysize)); rc = zpc_aes_xts_set_iv(aes_xts1, iv); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); rc = zpc_aes_xts_set_key(aes_xts2, aes_key2, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts2, iv); EXPECT_EQ(rc, 0); memset(aes_xts2->param_km, 0, AES_XTS_PROTKEYLEN(aes_xts2->aes_key1->keysize)); rc = zpc_aes_xts_encrypt(aes_xts2, c, m, 96); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); rc = zpc_aes_xts_set_key(aes_xts3, aes_key2, aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(aes_xts3, iv); EXPECT_EQ(rc, 0); memset(aes_xts3->param_km, 0, AES_XTS_PROTKEYLEN(aes_xts3->aes_key1->keysize)); rc = zpc_aes_xts_decrypt(aes_xts3, m, c, 96); EXPECT_EQ(rc, ZPC_ERROR_PROTKEYONLY); zpc_aes_xts_free(&aes_xts3); zpc_aes_xts_free(&aes_xts2); zpc_aes_xts_free(&aes_xts1); zpc_aes_key_free(&aes_key2); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_xts3, nullptr); EXPECT_EQ(aes_xts2, nullptr); EXPECT_EQ(aes_xts1, nullptr); EXPECT_EQ(aes_key2, nullptr); EXPECT_EQ(aes_key1, nullptr); } TEST(aes_xts, rederive_protected_key2) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); size_t keylen, msglen, ctlen, ivlen; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_xts *aes_xts; unsigned int flags; int type, rc; const char *keystr = "394c97881abd989d29c703e48a72b397a7acf51b59649eeea9b33274d8541df4"; const char *ivstr = "4b15c684a152d485fe9937d39b168c29"; const char *msgstr = "2f3b9dcfbae729583b1d1ffdd16bb6fe2757329435662a78f0"; const char *ctstr = "f3473802e38a3ffef4d4fb8e6aa266ebde553a64528a06463e"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 128, flags); u8 *key1 = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key1, nullptr); keylen /= 2; u8 *key2 = key1 + keylen; u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key1, key1); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, keylen * 8); if (rc) goto ret; } rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key2, key2); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key2, keylen * 8); if (rc) goto ret; } /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, 0); memset(aes_xts->param_pcc, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key2->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); memset(aes_xts->param_km, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key1->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_encrypt(aes_xts, buf, buf, msglen); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); } /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, 0); memset(aes_xts->param_pcc, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key2->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); memset(aes_xts->param_km, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key1->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_encrypt(aes_xts, buf, buf, msglen); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); } /* Decrypt */ memcpy(buf, ct, ctlen); memset(aes_xts->param_pcc, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key2->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); memset(aes_xts->param_km, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key1->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_decrypt(aes_xts, buf, buf, msglen); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); } /* Decrypt */ memcpy(buf, ct, ctlen); memset(aes_xts->param_pcc, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key2->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); memset(aes_xts->param_km, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key1->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_decrypt(aes_xts, buf, buf, msglen); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); } ret: zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); free(key1); free(iv); free(msg); free(ct); } TEST(aes_xts, reencipher) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); size_t keylen, msglen, ctlen, ivlen; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key1, *aes_key2; struct zpc_aes_xts *aes_xts; unsigned int flags; int type, rc; const char *keystr = "394c97881abd989d29c703e48a72b397a7acf51b59649eeea9b33274d8541df4"; const char *ivstr = "4b15c684a152d485fe9937d39b168c29"; const char *msgstr = "2f3b9dcfbae729583b1d1ffdd16bb6fe2757329435662a78f0"; const char *ctstr = "f3473802e38a3ffef4d4fb8e6aa266ebde553a64528a06463e"; u8 *key1 = testlib_hexstr2buf(keystr, &keylen); ASSERT_NE(key1, nullptr); keylen /= 2; u8 *key2 = key1 + keylen; u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 128, flags); TESTLIB_AES_NEW_MK_CHECK(type, mkvp, apqns); if (type == ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping reencipher test. Not applicable for UV secrets."); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&aes_xts); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key1, key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, keylen * 8); EXPECT_EQ(rc, 0); rc = zpc_aes_key_import_clear(aes_key2, key2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_reencipher(aes_key1, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key1->cur, 0, sizeof(aes_key1->cur)); /* destroy current secure key */ rc = zpc_aes_key_reencipher(aes_key2, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key2->cur, 0, sizeof(aes_key2->cur)); /* destroy current secure key */ /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, 0); memset(&aes_key1->prot, 0, sizeof(aes_key1->prot)); /* destroy cached protected key */ memset(&aes_key2->prot, 0, sizeof(aes_key2->prot)); /* destroy cached protected key */ memset(aes_xts->param_pcc, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key2->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); memset(&aes_key1->prot, 0, sizeof(aes_key1->prot)); /* destroy cached protected key */ memset(&aes_key2->prot, 0, sizeof(aes_key2->prot)); /* destroy cached protected key */ memset(aes_xts->param_km, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key1->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_encrypt(aes_xts, buf, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Encrypt */ memcpy(buf, msg, msglen); rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, 0); memset(&aes_key1->prot, 0, sizeof(aes_key1->prot)); /* destroy cached protected key */ memset(&aes_key2->prot, 0, sizeof(aes_key2->prot)); /* destroy cached protected key */ memset(aes_xts->param_pcc, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key2->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); memset(&aes_key1->prot, 0, sizeof(aes_key1->prot)); /* destroy cached protected key */ memset(&aes_key2->prot, 0, sizeof(aes_key2->prot)); /* destroy cached protected key */ memset(aes_xts->param_km, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key1->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_encrypt(aes_xts, buf, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); memset(&aes_key1->prot, 0, sizeof(aes_key1->prot)); /* destroy cached protected key */ memset(&aes_key2->prot, 0, sizeof(aes_key2->prot)); /* destroy cached protected key */ memset(aes_xts->param_pcc, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key2->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); memset(&aes_key1->prot, 0, sizeof(aes_key1->prot)); /* destroy cached protected key */ memset(&aes_key2->prot, 0, sizeof(aes_key2->prot)); /* destroy cached protected key */ memset(aes_xts->param_km, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key1->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_decrypt(aes_xts, buf, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); /* Decrypt */ memcpy(buf, ct, ctlen); memset(&aes_key1->prot, 0, sizeof(aes_key1->prot)); /* destroy cached protected key */ memset(&aes_key2->prot, 0, sizeof(aes_key2->prot)); /* destroy cached protected key */ memset(aes_xts->param_pcc, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key2->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); memset(&aes_key1->prot, 0, sizeof(aes_key1->prot)); /* destroy cached protected key */ memset(&aes_key2->prot, 0, sizeof(aes_key2->prot)); /* destroy cached protected key */ memset(aes_xts->param_km, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key1->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_decrypt(aes_xts, buf, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); free(key1); free(iv); free(msg); free(ct); } /* * This test assumes that the tester manually added the clear AES key * to the pvsecret list file, for example: * * 2 AES-128-KEY: * 0x8cf9659cd ... <- secret ID * 0x5e511208c7d50... <- clear key value * ... * * The test creates two pvsecret-type AES keys and two CCA or EP11 type * single AES keys with the given clear key material to compare results. * The specified APQN(s) decide if the single keys are CCA or EP11. */ TEST(aes_xts, pvsecret_kat) { struct zpc_aes_key *aes_key1, *aes_key2, *aes_key3, *aes_key4; struct zpc_aes_xts *ctx1, *ctx2; u8 iv[16], m[96], c[96], m_bak[96], c_bak[96]; const char *mkvp, *apqns[257]; unsigned int flags; int type, type2, rc, size; TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); size = testlib_env_aes_key_size(); type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); if (type != ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping pvsecret_kat test. Only applicable for UV secrets."); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags); TESTLIB_AES_XTS_KEY_SIZE_CHECK(size); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); TESTLIB_EC_NEW_MK_CHECK(type, mkvp, apqns); rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key3); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key4); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&ctx1); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_alloc(&ctx2); EXPECT_EQ(rc, 0); /* * key1 and key2 are created from pvsecret for ctx1. */ rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, size); EXPECT_EQ(rc, 0); rc = testlib_set_aes_key_from_pvsecret(aes_key1, size); if (rc) goto ret; rc = testlib_set_aes_key_from_pvsecret(aes_key2, size); if (rc) goto ret; rc = zpc_aes_xts_set_key(ctx1, aes_key1, aes_key2); EXPECT_EQ(rc, 0); /* * key3 and key4 are normal AES keys and contain clear key material from * list file. We first try to create a CCA type key with the given APQN(s), * if this fails we retry with EP11. */ type2 = ZPC_AES_KEY_TYPE_CCA_DATA; while (1) { rc = zpc_aes_key_set_type(aes_key3, type2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key4, type2); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key3, mkvp); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_mkvp(aes_key4, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key3, apqns); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_apqns(aes_key4, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key3, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_flags(aes_key4, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key3, size); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key4, size); EXPECT_EQ(rc, 0); rc = testlib_set_aes_key_from_file(aes_key3, type2, size); rc = testlib_set_aes_key_from_file(aes_key4, type2, size); if (rc == ZPC_ERROR_IOCTLCLR2SECK2) { type2 = ZPC_AES_KEY_TYPE_EP11; continue; } if (rc) goto ret; else break; } rc = zpc_aes_xts_set_key(ctx2, aes_key3, aes_key4); EXPECT_EQ(rc, 0); memcpy(m_bak, m, 96); /* Now encrypt with both ctx and compare result */ rc = zpc_aes_xts_set_iv(ctx1, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(ctx1, c, m, 96); EXPECT_EQ(rc, 0); memcpy(c_bak, c, 96); rc = zpc_aes_xts_set_iv(ctx2, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(ctx2, c, m, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(c, c_bak, 96) == 0); /* Now encrypt with ctx1 and decrypt with ctx2 */ rc = zpc_aes_xts_set_iv(ctx1, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_encrypt(ctx1, c, m, 96); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_iv(ctx2, iv); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_decrypt(ctx2, m, c, 96); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(m, m_bak, 96) == 0); ret: zpc_aes_xts_free(&ctx1); EXPECT_EQ(ctx1, nullptr); zpc_aes_xts_free(&ctx2); EXPECT_EQ(ctx2, nullptr); zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); zpc_aes_key_free(&aes_key3); EXPECT_EQ(aes_key3, nullptr); zpc_aes_key_free(&aes_key4); EXPECT_EQ(aes_key3, nullptr); } static void __task(struct zpc_aes_key *aes_key1, struct zpc_aes_key *aes_key2) { struct zpc_aes_xts *aes_xts; unsigned char buf[4096]; size_t ivlen, msglen, ctlen; int rc, i; const char *ivstr = "4b15c684a152d485fe9937d39b168c29"; const char *msgstr = "2f3b9dcfbae729583b1d1ffdd16bb6fe2757329435662a78f0"; const char *ctstr = "f3473802e38a3ffef4d4fb8e6aa266ebde553a64528a06463e"; u8 *iv = testlib_hexstr2buf(ivstr, &ivlen); ASSERT_NE(iv, nullptr); u8 *msg = testlib_hexstr2buf(msgstr, &msglen); ASSERT_NE(msg, nullptr); u8 *ct = testlib_hexstr2buf(ctstr, &ctlen); ASSERT_NE(ct, nullptr); rc = zpc_aes_xts_alloc(&aes_xts); EXPECT_EQ(rc, 0); rc = zpc_aes_xts_set_key(aes_xts, aes_key1, aes_key2); EXPECT_EQ(rc, 0); for (i = 0; i < 1000; i++) { /* Encrypt */ memcpy(buf, msg, msglen); memset(aes_xts->param_pcc, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key2->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); memset(aes_xts->param_km, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key1->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_encrypt(aes_xts, buf, buf, ctlen); EXPECT_EQ(rc, 0); if (aes_key1->type != ZPC_AES_KEY_TYPE_PVSECRET) { EXPECT_TRUE(memcmp(buf, ct, ctlen) == 0); } /* Decrypt */ if (aes_key1->type != ZPC_AES_KEY_TYPE_PVSECRET) { memcpy(buf, ct, ctlen); } memset(aes_xts->param_pcc, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key2->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_set_iv(aes_xts, iv); EXPECT_EQ(rc, 0); memset(aes_xts->param_km, 0, AES_XTS_PROTKEYLEN(aes_xts->aes_key1->keysize)); /* force WKaVP mismatch */ rc = zpc_aes_xts_decrypt(aes_xts, buf, buf, msglen); EXPECT_EQ(rc, 0); EXPECT_TRUE(memcmp(buf, msg, msglen) == 0); } zpc_aes_xts_free(&aes_xts); EXPECT_EQ(aes_xts, nullptr); free(iv); free(msg); free(ct); } TEST(aes_xts, threads) { TESTLIB_ENV_AES_KEY_CHECK(); TESTLIB_AES_XTS_HW_CAPS_CHECK(); size_t keylen; const char *mkvp, *apqns[257]; struct zpc_aes_key *aes_key1, *aes_key2; unsigned int flags; int type, rc, i; std::thread *t[500]; const char *keystr = "394c97881abd989d29c703e48a72b397a7acf51b59649eeea9b33274d8541df4"; type = testlib_env_aes_key_type(); flags = testlib_env_aes_key_flags(); mkvp = testlib_env_aes_key_mkvp(); (void)testlib_env_aes_key_apqns(apqns); TESTLIB_AES_KERNEL_CAPS_CHECK(type); TESTLIB_AES_SW_CAPS_CHECK(type); TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, 128, flags); TESTLIB_AES_NEW_MK_CHECK(type, mkvp, apqns); u8 *key1 = testlib_hexstr2buf(keystr, &keylen); keylen /= 2; u8 *key2 = key1 + keylen; rc = zpc_aes_key_alloc(&aes_key1); EXPECT_EQ(rc, 0); rc = zpc_aes_key_alloc(&aes_key2); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_type(aes_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key1, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key1, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key1, key1); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key1, keylen * 8); if (rc) goto ret; } rc = zpc_aes_key_set_type(aes_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_aes_key_set_mkvp(aes_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_aes_key_set_apqns(aes_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_aes_key_set_flags(aes_key2, flags); EXPECT_EQ(rc, 0); rc = zpc_aes_key_set_size(aes_key2, keylen * 8); EXPECT_EQ(rc, 0); if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_import_clear(aes_key2, key2); EXPECT_EQ(rc, 0); } else { rc = testlib_set_aes_key_from_pvsecret(aes_key2, keylen * 8); if (rc) goto ret; } for (i = 0; i < 500; i++) { t[i] = new std::thread(__task, aes_key1, aes_key2); } /* Do something with key object while threads are working with it. */ if (type != ZPC_AES_KEY_TYPE_PVSECRET) { rc = zpc_aes_key_reencipher(aes_key1, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key1->cur, 0, sizeof(aes_key1->cur)); /* destroy current secure key */ rc = zpc_aes_key_reencipher(aes_key2, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&aes_key2->cur, 0, sizeof(aes_key2->cur)); /* destroy current secure key */ } for (i = 0; i < 500; i++) { memset(&aes_key1->prot, 0, sizeof(aes_key1->prot)); /* destroy cached protected key */ usleep(1); memset(&aes_key2->prot, 0, sizeof(aes_key2->prot)); /* destroy cached protected key */ } for (i = 0; i < 500; i++) { t[i]->join(); delete t[i]; } ret: zpc_aes_key_free(&aes_key1); EXPECT_EQ(aes_key1, nullptr); zpc_aes_key_free(&aes_key2); EXPECT_EQ(aes_key2, nullptr); free(key1); } libzpc-1.3.0/test/t_ecc_key.cc000066400000000000000000000543761475140344100162330ustar00rootroot00000000000000/* * Copyright IBM Corp. 2022 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "testlib.h" #include "gtest/gtest.h" #include "zpc/ecc_key.h" #include "zpc/error.h" extern const struct EC_TEST_VECTOR ec_tv[]; TEST(ec_key, alloc) { struct zpc_ec_key *ec_key; int rc; TESTLIB_ENV_EC_KEY_CHECK(); rc = zpc_ec_key_alloc(NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); ec_key = NULL; rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); ec_key = (struct zpc_ec_key *)&ec_key; rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ec_key, free) { struct zpc_ec_key *ec_key; int rc; TESTLIB_ENV_EC_KEY_CHECK(); zpc_ec_key_free(NULL); ec_key = NULL; zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ec_key, set_curve) { struct zpc_ec_key *ec_key; int rc; TESTLIB_ENV_EC_KEY_CHECK(); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(NULL, ZPC_EC_CURVE_P256); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_curve(NULL, ZPC_EC_CURVE_P384); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_curve(NULL, ZPC_EC_CURVE_P521); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_curve(NULL, ZPC_EC_CURVE_ED25519); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_curve(NULL, ZPC_EC_CURVE_ED448); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_curve(ec_key, ZPC_EC_CURVE_P256); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key, ZPC_EC_CURVE_P384); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key, ZPC_EC_CURVE_P521); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key, ZPC_EC_CURVE_ED25519); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key, ZPC_EC_CURVE_ED448); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key, ZPC_EC_CURVE_INVALID); EXPECT_EQ(rc, ZPC_ERROR_EC_INVALID_CURVE); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ec_key, set_type_cca) { struct zpc_ec_key *ec_key; int rc; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_SW_CAPS_CHECK(ZPC_EC_KEY_TYPE_CCA); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(NULL, -1); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_type(NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_type(NULL, ZPC_EC_KEY_TYPE_CCA); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_type(NULL, 4); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_type(ec_key, -1); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPE); rc = zpc_ec_key_set_type(ec_key, 0); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPE); rc = zpc_ec_key_set_type(ec_key, ZPC_EC_KEY_TYPE_CCA); EXPECT_EQ(rc, 0); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ec_key, set_type_ep11) { struct zpc_ec_key *ec_key; int rc; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_SW_CAPS_CHECK(ZPC_EC_KEY_TYPE_EP11); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(NULL, -1); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_type(NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_type(NULL, ZPC_EC_KEY_TYPE_EP11); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_type(NULL, 4); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_type(ec_key, -1); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPE); rc = zpc_ec_key_set_type(ec_key, 0); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPE); rc = zpc_ec_key_set_type(ec_key, ZPC_EC_KEY_TYPE_EP11 + 1); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPE); rc = zpc_ec_key_set_type(ec_key, ZPC_EC_KEY_TYPE_EP11); EXPECT_EQ(rc, 0); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ec_key, set_type_pvsecret) { struct zpc_ec_key *ec_key; int rc; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_SW_CAPS_CHECK(ZPC_EC_KEY_TYPE_PVSECRET); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(NULL, -1); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_type(NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_type(NULL, ZPC_EC_KEY_TYPE_PVSECRET); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_type(NULL, 4); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_type(ec_key, -1); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPE); rc = zpc_ec_key_set_type(ec_key, 0); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPE); rc = zpc_ec_key_set_type(ec_key, ZPC_EC_KEY_TYPE_PVSECRET + 1); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPE); rc = zpc_ec_key_set_type(ec_key, ZPC_EC_KEY_TYPE_PVSECRET); EXPECT_EQ(rc, 0); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ec_key, set_flags) { struct zpc_ec_key *ec_key; int rc; TESTLIB_ENV_EC_KEY_CHECK(); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_flags(NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_flags(ec_key, -1); EXPECT_EQ(rc, 0); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ec_key, set_mkvp) { struct zpc_ec_key *ec_key; const char *mkvp; unsigned int flags; int rc, type; TESTLIB_ENV_EC_KEY_CHECK(); type = testlib_env_ec_key_type(); flags = testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); TESTLIB_EC_SW_CAPS_CHECK(type); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_mkvp(NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_mkvp(NULL, mkvp); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_mkvp(ec_key, NULL); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_mkvp(ec_key, mkvp); if (mkvp) EXPECT_EQ(rc, ZPC_ERROR_KEYTYPENOTSET); else EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ec_key, set_apqns) { struct zpc_ec_key *ec_key; const char *apqns[] = {"01.0037", "\n01.0037\t ", NULL}; /* apqn example */ int rc; TESTLIB_ENV_EC_KEY_CHECK(); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_apqns(NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_apqns(NULL, apqns); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_set_apqns(ec_key, NULL); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_TRUE(rc == 0 || rc == ZPC_ERROR_WKVPMISMATCH || rc == ZPC_ERROR_APQNS_INVALID_VERSION ); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ec_key, import_clear) { struct zpc_ec_key *ec_key; unsigned int pubkeylen, privkeylen; const char *apqns[257]; unsigned int flags; int rc, type; zpc_ec_curve_t curve; const char *mkvp; TESTLIB_ENV_EC_KEY_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags = testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp,apqns); const u8 *pubkey = ec_tv[curve].pubkey; const u8 *privkey = ec_tv[curve].privkey; pubkeylen = ec_tv[curve].pubkey_len; privkeylen = ec_tv[curve].privkey_len; rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_import_clear(NULL, NULL, 0, NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_import_clear(NULL, pubkey, pubkeylen, privkey, privkeylen); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_import_clear(ec_key, NULL, 0, NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_EC_NO_KEY_PARTS); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_import_clear(ec_key, pubkey, pubkeylen, privkey, privkeylen); EXPECT_EQ(rc, ZPC_ERROR_APQNSNOTSET); } if (mkvp == NULL) { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); rc = zpc_ec_key_import_clear(ec_key, pubkey, pubkeylen, privkey, privkeylen); EXPECT_EQ(rc, ZPC_ERROR_EC_CURVE_NOTSET); } rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); if (mkvp == NULL) { rc = zpc_ec_key_import_clear(ec_key, pubkey, pubkeylen, privkey, privkeylen); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPENOTSET); } rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_import_clear(ec_key, pubkey, 5, privkey, privkeylen); EXPECT_EQ(rc, ZPC_ERROR_EC_PUBKEY_LENGTH); rc = zpc_ec_key_import_clear(ec_key, pubkey, pubkeylen, privkey, 5); EXPECT_EQ(rc, ZPC_ERROR_EC_PRIVKEY_LENGTH); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_import_clear(ec_key, pubkey, pubkeylen, privkey, privkeylen); EXPECT_EQ(rc, 0); } else { /* Only public keys can be imported/added for pvsecret-type keys */ rc = zpc_ec_key_import_clear(ec_key, pubkey, pubkeylen, NULL, 0); EXPECT_EQ(rc, 0); } zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ec_key, generate) { struct zpc_ec_key *ec_key; unsigned int flags; const char *apqns[257]; int rc, type; zpc_ec_curve_t curve; const char *mkvp; TESTLIB_ENV_EC_KEY_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags= testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_generate(NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_generate(ec_key); EXPECT_EQ(rc, ZPC_ERROR_EC_CURVE_NOTSET); if (mkvp == NULL) { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); rc = zpc_ec_key_generate(ec_key); EXPECT_EQ(rc, ZPC_ERROR_EC_CURVE_NOTSET); } rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); if (mkvp == NULL) { rc = zpc_ec_key_generate(ec_key); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPENOTSET); } rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_generate(ec_key); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_generate(ec_key); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPE); } zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ec_key, reencipher) { struct zpc_ec_key *ec_key; unsigned int flags; const char *apqns[257]; int rc, type; zpc_ec_curve_t curve; const char *mkvp; TESTLIB_ENV_EC_KEY_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags= testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); TESTLIB_EC_NEW_MK_CHECK(type, mkvp, apqns); if (type == ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping reencipher test. Not applicable for UV secrets."); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_generate(ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_reencipher(ec_key, ZPC_EC_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ec_key, export) { struct zpc_ec_key *ec_key, *ec_key2; u8 buf[2000], buf2[2000]; unsigned int buflen, buflen2, flags; const char *apqns[257]; int rc, type; zpc_ec_curve_t curve; const char *mkvp; TESTLIB_ENV_EC_KEY_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags= testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); rc = zpc_ec_key_export(NULL, NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_alloc(&ec_key2); EXPECT_EQ(rc, 0); rc = zpc_ec_key_export(ec_key, NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG3NULL); rc = zpc_ec_key_export(ec_key, NULL, &buflen); EXPECT_EQ(rc, ZPC_ERROR_EC_NO_KEY_PARTS); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_generate(ec_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_ec_key_from_pvsecret(ec_key, type, curve); if (rc) goto ret; } buflen = 0; rc = zpc_ec_key_export(ec_key, buf, &buflen); EXPECT_EQ(rc, ZPC_ERROR_SMALLOUTBUF); rc = zpc_ec_key_export(ec_key, NULL, &buflen); EXPECT_EQ(rc, 0); EXPECT_GT(buflen, 0UL); rc = zpc_ec_key_export(ec_key, buf, &buflen); EXPECT_EQ(rc, 0); /* Import this secure key token into a 2nd key */ rc = zpc_ec_key_set_type(ec_key2, type); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_flags(ec_key2, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key2, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_import(ec_key2, buf, buflen); EXPECT_EQ(rc, 0); /* And export it again */ buflen2 = sizeof(buf2); rc = zpc_ec_key_export(ec_key2, buf2, &buflen2); EXPECT_EQ(rc, 0); EXPECT_EQ(buflen, buflen2); EXPECT_TRUE(memcmp(buf2, buf, buflen) == 0); ret: zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); zpc_ec_key_free(&ec_key2); EXPECT_EQ(ec_key2, nullptr); } TEST(ec_key, export_public) { struct zpc_ec_key *ec_key; u8 buf[132]; unsigned int buflen, flags; const char *apqns[257]; int rc, type; zpc_ec_curve_t curve; const char *mkvp; TESTLIB_ENV_EC_KEY_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags= testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); rc = zpc_ec_key_export_public(NULL, NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_export_public(ec_key, NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG3NULL); rc = zpc_ec_key_export_public(ec_key, NULL, &buflen); EXPECT_EQ(rc, ZPC_ERROR_EC_PUBKEY_NOTSET); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_generate(ec_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_ec_key_from_pvsecret(ec_key, type, curve); if (rc) goto ret; } buflen = 0; rc = zpc_ec_key_export_public(ec_key, buf, &buflen); EXPECT_EQ(rc, ZPC_ERROR_SMALLOUTBUF); rc = zpc_ec_key_export_public(ec_key, NULL, &buflen); EXPECT_EQ(rc, 0); EXPECT_GT(buflen, 0UL); rc = zpc_ec_key_export_public(ec_key, buf, &buflen); EXPECT_EQ(rc, 0); ret: zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ec_key, import) { struct zpc_ec_key *ec_key, *ec_key2; u8 buf[10000], buf2[10000]; unsigned int buflen = sizeof(buf); unsigned int buf2len = sizeof(buf2); unsigned int flags; const char *apqns[257]; const char *mkvp; int rc, type; zpc_ec_curve_t curve; TESTLIB_ENV_EC_KEY_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags= testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_alloc(&ec_key2); EXPECT_EQ(rc, 0); rc = zpc_ec_key_import(NULL, NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ec_key_import(ec_key, NULL, 0); EXPECT_EQ(rc, ZPC_ERROR_ARG2NULL); rc = zpc_ec_key_import(ec_key, buf, 63); EXPECT_EQ(rc, ZPC_ERROR_ARG3RANGE); rc = zpc_ec_key_import(ec_key, buf, 3000); EXPECT_EQ(rc, ZPC_ERROR_ARG3RANGE); rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key2, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_import(ec_key, buf, 226); EXPECT_EQ(rc, ZPC_ERROR_KEYTYPENOTSET); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_mkvp(ec_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_apqns(ec_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_import(ec_key, buf, 333); EXPECT_TRUE(rc == ZPC_ERROR_EC_NO_CCA_SECUREKEY_TOKEN || rc == ZPC_ERROR_EC_NO_EP11_SECUREKEY_TOKEN || rc == ZPC_ERROR_ARG3RANGE); rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_generate(ec_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_ec_key_from_pvsecret(ec_key, type, curve); if (rc) goto ret; } rc = zpc_ec_key_export(ec_key, buf, &buflen); EXPECT_EQ(rc, 0); rc = zpc_ec_key_import(ec_key2, buf, buflen); EXPECT_EQ(rc, 0); rc = zpc_ec_key_export(ec_key2, buf2, &buf2len); EXPECT_EQ(rc, 0); EXPECT_EQ(buf2len, buflen); EXPECT_TRUE(memcmp(buf2, buf, buflen) == 0); ret: zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); zpc_ec_key_free(&ec_key2); EXPECT_EQ(ec_key2, nullptr); } TEST(ec_key, spki_test) { struct zpc_ec_key *ec_key, *ec_key2; unsigned int pubkeylen, privkeylen, blob_len, pubkey_offset; u8 buf[3000] = {0}, buf2[3000] = {0}, buf3[132] = {0}, buf4[3000] = {0}; unsigned int buflen = sizeof(buf); unsigned int buf2len = sizeof(buf2); unsigned int buf3len = sizeof(buf3); unsigned int buf4len = sizeof(buf4); unsigned int flags; const char *apqns[257]; const char *mkvp; int rc, type; zpc_ec_curve_t curve; /* These numbers are derived from the pxxx_maced_spki_t structs in ep11.h, * applications should have their own way of handling SPKIs. */ unsigned int curve2pubkey_offset[] = { 27, 24, 26, 21, 21 }; struct ep11kblob_header { u8 type; /* always 0x00 */ u8 hver; /* header version, currently needs to be 0x00 */ u16 len; /* total length in bytes (including this header) */ u8 version; /* PKEY_TYPE_EP11_AES or PKEY_TYPE_EP11_ECC */ u8 res0; /* unused */ u16 bitlen; /* clear key bit len, 0 for unknown */ u8 res1[8]; /* unused */ }; TESTLIB_ENV_EC_KEY_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags= testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); if (type != ZPC_EC_KEY_TYPE_EP11) GTEST_SKIP_("Skipping spki_test. Only supported for EP11 type keys."); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); const u8 *pubkey = ec_tv[curve].pubkey; const u8 *privkey = ec_tv[curve].privkey; pubkeylen = ec_tv[curve].pubkey_len; privkeylen = ec_tv[curve].privkey_len; rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_alloc(&ec_key2); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key2, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_mkvp(ec_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_apqns(ec_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_flags(ec_key2, flags); EXPECT_EQ(rc, 0); /* Test (1): Import private key only */ rc = zpc_ec_key_import_clear(ec_key, NULL, 0, privkey, privkeylen); EXPECT_EQ(rc, 0); /* Export key, there is no public key spki available. The buflen must * be equal to the length given inside the secure key blob. */ rc = zpc_ec_key_export(ec_key, buf, &buflen); EXPECT_EQ(rc, 0); EXPECT_EQ(buflen, ((struct ep11kblob_header *)buf)->len); /* Test (2): Add public key, now an spki is created internally */ rc = zpc_ec_key_import_clear(ec_key, pubkey, pubkeylen, NULL, 0); EXPECT_EQ(rc, 0); /* Export key: buf2len must now be greater than buflen, because of the * appended spki. */ rc = zpc_ec_key_export(ec_key, buf2, &buf2len); EXPECT_EQ(rc, 0); EXPECT_GT(buf2len, buflen); /* Public key inside the spki must be identical to original pubkey */ blob_len = ((struct ep11kblob_header *)buf2)->len; pubkey_offset = curve2pubkey_offset[curve]; EXPECT_TRUE(memcmp(pubkey, buf2 + blob_len + pubkey_offset, pubkeylen) == 0); /* Test (3): Now import [blob||spki] into a second key */ rc = zpc_ec_key_import(ec_key2, buf2, buf2len); EXPECT_EQ(rc, 0); /* Export public key only: must be identical to original public key */ rc = zpc_ec_key_export_public(ec_key2, buf3, &buf3len); EXPECT_EQ(rc, 0); EXPECT_EQ(buf3len, pubkeylen); EXPECT_TRUE(memcmp(buf3, pubkey, buf3len) == 0); /* Export secure key: must be [blob||spki] as previously imported */ rc = zpc_ec_key_export(ec_key2, buf4, &buf4len); EXPECT_EQ(rc, 0); EXPECT_EQ(buf4len, buf2len); EXPECT_TRUE(memcmp(buf4, buf2, buf4len) == 0); /* Test (4): Generate a new key pair */ rc = zpc_ec_key_generate(ec_key); EXPECT_EQ(rc, 0); /* Export public key */ rc = zpc_ec_key_export_public(ec_key2, buf3, &buf3len); EXPECT_EQ(rc, 0); /* Export [blob||spki] */ buflen = sizeof(buf); rc = zpc_ec_key_export(ec_key2, buf, &buflen); EXPECT_EQ(rc, 0); /* Public key must be identical to public key inside the spki */ blob_len = ((struct ep11kblob_header *)buf)->len; pubkey_offset = curve2pubkey_offset[curve]; EXPECT_TRUE(memcmp(buf3, buf + blob_len + pubkey_offset, buf3len) == 0); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); zpc_ec_key_free(&ec_key2); EXPECT_EQ(ec_key2, nullptr); } libzpc-1.3.0/test/t_ecdsa_ctx.cc000066400000000000000000001323711475140344100165560ustar00rootroot00000000000000/* * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "testlib.h" #include "gtest/gtest.h" #include "zpc/error.h" #include "ecc_key_local.h" /* de-opaquify struct zpc_ecc_key */ #include "ecdsa_ctx_local.h" /* de-opaquify struct zpc_ecc_ctx */ #include "zpc/ecdsa_ctx.h" #include #include #include #include extern const struct EC_TEST_VECTOR ec_tv[]; void force_WKaVP_mismatch(struct zpc_ecdsa_ctx *ctx) { if (ctx == NULL || ctx->ec_key == NULL) return; switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: memset(ctx->p256_sign_param.prot, 0, sizeof(ctx->p256_sign_param.prot)); memset(ctx->p256_sign_param.wkvp, 0, sizeof(ctx->p256_sign_param.wkvp)); break; case ZPC_EC_CURVE_P384: memset(ctx->p384_sign_param.prot, 0, sizeof(ctx->p384_sign_param.prot)); memset(ctx->p384_sign_param.wkvp, 0, sizeof(ctx->p384_sign_param.wkvp)); break; case ZPC_EC_CURVE_P521: memset(ctx->p521_sign_param.prot, 0, sizeof(ctx->p521_sign_param.prot)); memset(ctx->p521_sign_param.wkvp, 0, sizeof(ctx->p521_sign_param.wkvp)); break; case ZPC_EC_CURVE_ED25519: memset(ctx->ed25519_sign_param.prot, 0, sizeof(ctx->ed25519_sign_param.prot)); memset(ctx->ed25519_sign_param.wkvp, 0, sizeof(ctx->ed25519_sign_param.wkvp)); break; case ZPC_EC_CURVE_ED448: memset(ctx->ed448_sign_param.prot, 0, sizeof(ctx->ed448_sign_param.prot)); memset(ctx->ed448_sign_param.wkvp, 0, sizeof(ctx->ed448_sign_param.wkvp)); break; default: break; } } static void __run_json(const char *json); TEST(ecdsa_ctx, alloc) { struct zpc_ecdsa_ctx *ec_ctx; int rc; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_HW_CAPS_CHECK(); rc = zpc_ecdsa_ctx_alloc(NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); ec_ctx = NULL; rc = zpc_ecdsa_ctx_alloc(&ec_ctx); EXPECT_EQ(rc, 0); zpc_ecdsa_ctx_free(&ec_ctx); EXPECT_EQ(ec_ctx, nullptr); ec_ctx = (struct zpc_ecdsa_ctx *)&ec_ctx; rc = zpc_ecdsa_ctx_alloc(&ec_ctx); EXPECT_EQ(rc, 0); zpc_ecdsa_ctx_free(&ec_ctx); EXPECT_EQ(ec_ctx, nullptr); } TEST(ecdsa_ctx, free) { struct zpc_ecdsa_ctx *ec_ctx; int rc; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_HW_CAPS_CHECK(); zpc_ecdsa_ctx_free(NULL); ec_ctx = NULL; zpc_ecdsa_ctx_free(&ec_ctx); EXPECT_EQ(ec_ctx, nullptr); rc = zpc_ecdsa_ctx_alloc(&ec_ctx); EXPECT_EQ(rc, 0); zpc_ecdsa_ctx_free(&ec_ctx); EXPECT_EQ(ec_ctx, nullptr); } TEST(ecdsa_ctx, set_key) { struct zpc_ec_key *ec_key; struct zpc_ecdsa_ctx *ec_ctx; unsigned int pubkeylen, privkeylen, flags = 0; const char *mkvp, *apqns[257]; int rc, type; zpc_ec_curve_t curve; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_HW_CAPS_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags = testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); const u8 *pubkey = ec_tv[curve].pubkey; const u8 *privkey = ec_tv[curve].privkey; pubkeylen = ec_tv[curve].pubkey_len; privkeylen = ec_tv[curve].privkey_len; rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_alloc(&ec_ctx); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_set_key(ec_ctx, ec_key); EXPECT_EQ(rc, ZPC_ERROR_EC_NO_KEY_PARTS); rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_import_clear(ec_key, pubkey, pubkeylen, privkey, privkeylen); EXPECT_EQ(rc, 0); } else { rc = testlib_set_ec_key_from_pvsecret(ec_key, type, curve); if (rc) goto ret; } rc = zpc_ecdsa_ctx_set_key(NULL, NULL); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ecdsa_ctx_set_key(NULL, ec_key); EXPECT_EQ(rc, ZPC_ERROR_ARG1NULL); rc = zpc_ecdsa_ctx_set_key(ec_ctx, NULL); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_set_key(ec_ctx, ec_key); EXPECT_EQ(rc, 0); ret: zpc_ecdsa_ctx_free(&ec_ctx); EXPECT_EQ(ec_ctx, nullptr); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ecdsa_ctx, sign) { struct zpc_ec_key *ec_key; struct zpc_ecdsa_ctx *ec_ctx; const char *mkvp, *apqns[257]; u8 msg[1000], signature[200]; unsigned int msg_len, sig_len, flags; int rc, type; zpc_ec_curve_t curve; const unsigned int test_msglen_from_curve[] = { 32, 48, 64, 500, 1000 }; const unsigned int expected_siglen_from_curve[] = { 64, 96, 132, 64, 114 }; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_HW_CAPS_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags = testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_alloc(&ec_ctx); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_generate(ec_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_ec_key_from_pvsecret(ec_key, type, curve); if (rc) goto ret; } rc = zpc_ecdsa_ctx_set_key(ec_ctx, ec_key); EXPECT_EQ(rc, 0); sig_len = sizeof(signature); msg_len = test_msglen_from_curve[curve]; /* Check 'length_only': returned sig_len must match with expected len */ rc = zpc_ecdsa_sign(ec_ctx, msg, msg_len, NULL, &sig_len); EXPECT_EQ(rc, 0); EXPECT_EQ(sig_len, expected_siglen_from_curve[curve]); /* Now perform the sign */ rc = zpc_ecdsa_sign(ec_ctx, msg, msg_len, signature, &sig_len); EXPECT_EQ(rc, 0); ret: zpc_ecdsa_ctx_free(&ec_ctx); EXPECT_EQ(ec_ctx, nullptr); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ecdsa_ctx, verify) { struct zpc_ec_key *ec_key, *ec_key2, *ec_key3; struct zpc_ecdsa_ctx *ec_ctx; const char *mkvp, *apqns[257]; u8 signature[200]; u8 buf[200]; unsigned int signature_len, hash_len, sig_len, buflen; unsigned int pubkeylen, flags; int rc, type; zpc_ec_curve_t curve; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_HW_CAPS_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags = testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); const u8 *pubkey = ec_tv[curve].pubkey; const u8 *hash = ec_tv[curve].msg; const u8 *sig = ec_tv[curve].sig; pubkeylen = ec_tv[curve].pubkey_len; hash_len = ec_tv[curve].msg_len; sig_len = ec_tv[curve].sig_len; rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_alloc(&ec_key2); EXPECT_EQ(rc, 0); rc = zpc_ec_key_alloc(&ec_key3); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_alloc(&ec_ctx); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_generate(ec_key); EXPECT_EQ(rc, 0); } else { rc = testlib_set_ec_key_from_pvsecret(ec_key, type, curve); if (rc) goto ret; } rc = zpc_ecdsa_ctx_set_key(ec_ctx, ec_key); EXPECT_EQ(rc, 0); /* Create local signature with given NIST key */ signature_len = sizeof(signature); rc = zpc_ecdsa_sign(ec_ctx, hash, hash_len, signature, &signature_len); EXPECT_EQ(rc, 0); EXPECT_EQ(signature_len, sig_len); /* Export public key ... */ buflen = sizeof(buf); rc = zpc_ec_key_export_public(ec_key, buf, &buflen); EXPECT_EQ(rc, 0); EXPECT_GT(buflen, 0UL); /* Create a 2nd key with only the public key set */ rc = zpc_ec_key_set_type(ec_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_curve(ec_key2, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_flags(ec_key2, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_import_clear(ec_key2, buf, buflen, NULL, 0); EXPECT_EQ(rc, 0); /* Overwrite old key in ctx with new public-only key */ rc = zpc_ecdsa_ctx_set_key(ec_ctx, ec_key2); EXPECT_EQ(rc, 0); /* Now verify locally created signature with the public-only key */ rc = zpc_ecdsa_verify(ec_ctx, hash, hash_len, signature, signature_len); EXPECT_EQ(rc, 0); /* Import public key from NIST test into a new key3 */ rc = zpc_ec_key_set_type(ec_key3, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key3, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key3, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_curve(ec_key3, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_flags(ec_key3, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_import_clear(ec_key3, pubkey, pubkeylen, NULL, 0); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_set_key(ec_ctx, ec_key3); EXPECT_EQ(rc, 0); /* And verify NIST signature with the NIST public-only key */ rc = zpc_ecdsa_verify(ec_ctx, hash, hash_len, sig, sig_len); EXPECT_EQ(rc, 0); ret: zpc_ecdsa_ctx_free(&ec_ctx); EXPECT_EQ(ec_ctx, nullptr); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); zpc_ec_key_free(&ec_key2); EXPECT_EQ(ec_key2, nullptr); zpc_ec_key_free(&ec_key3); EXPECT_EQ(ec_key3, nullptr); } TEST(ecdsa_ctx, sv) { struct zpc_ec_key *ec_key1, *ec_key2; struct zpc_ecdsa_ctx *ec_ctx1, *ec_ctx2; u8 sigbuf[200]; unsigned int hash_len, sig_len, pubkeylen, privkeylen; const char *mkvp, *apqns[257]; unsigned int flags; int rc, type; zpc_ec_curve_t curve; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_HW_CAPS_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags = testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); const u8 *pubkey = ec_tv[curve].pubkey; const u8 *privkey = ec_tv[curve].privkey; const u8 *hash = ec_tv[curve].msg; const u8 *sig = ec_tv[curve].sig; pubkeylen = ec_tv[curve].pubkey_len; privkeylen = ec_tv[curve].privkey_len; hash_len = ec_tv[curve].msg_len; sig_len = ec_tv[curve].sig_len; rc = zpc_ec_key_alloc(&ec_key1); EXPECT_EQ(rc, 0); rc = zpc_ec_key_alloc(&ec_key2); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_alloc(&ec_ctx1); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_alloc(&ec_ctx2); EXPECT_EQ(rc, 0); /* Import NIST test key into ec_key1 */ rc = zpc_ec_key_set_curve(ec_key1, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key1, flags); EXPECT_EQ(rc, 0); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_import_clear(ec_key1, pubkey, pubkeylen, privkey, privkeylen); EXPECT_EQ(rc, 0); } else { rc = testlib_set_ec_key_from_pvsecret(ec_key1, type, curve); if (rc) goto ret; } rc = zpc_ecdsa_ctx_set_key(ec_ctx1, ec_key1); EXPECT_EQ(rc, 0); /* Import NIST test key into ec_key2 */ rc = zpc_ec_key_set_curve(ec_key2, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key2, flags); EXPECT_EQ(rc, 0); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_import_clear(ec_key2, pubkey, pubkeylen, privkey, privkeylen); EXPECT_EQ(rc, 0); } else { rc = testlib_set_ec_key_from_pvsecret(ec_key2, type, curve); if (rc) goto ret; } rc = zpc_ecdsa_ctx_set_key(ec_ctx2, ec_key2); EXPECT_EQ(rc, 0); /* Sign with first key */ rc = zpc_ecdsa_sign(ec_ctx1, hash, hash_len, sigbuf, &sig_len); EXPECT_EQ(rc, 0); /* Verify created signature with 1st key */ rc = zpc_ecdsa_verify(ec_ctx1, hash, hash_len, sigbuf, sig_len); EXPECT_EQ(rc, 0); /* Verify created signature with 2nd key */ rc = zpc_ecdsa_verify(ec_ctx2, hash, hash_len, sigbuf, sig_len); EXPECT_EQ(rc, 0); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { /* Verify known signature from test vector with 1st key */ rc = zpc_ecdsa_verify(ec_ctx1, hash, hash_len, sig, sig_len); EXPECT_EQ(rc, 0); /* Verify known signature from test vector with 2nd key */ rc = zpc_ecdsa_verify(ec_ctx2, hash, hash_len, sig, sig_len); EXPECT_EQ(rc, 0); } /* Create a random key. Note that random EC protected keys are not possible, * because, unlike AES, we always have to create a secure key first via * the host libs. So we cannot unset apqns as done in the aes tests. */ rc = zpc_ecdsa_ctx_set_key(ec_ctx1, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_set_key(ec_ctx2, NULL); /* Unset key. */ EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key1, curve); EXPECT_EQ(rc, 0); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_generate(ec_key1); EXPECT_EQ(rc, 0); } else { rc = testlib_set_ec_key_from_pvsecret(ec_key1, type, curve); if (rc) goto ret; } rc = zpc_ecdsa_ctx_set_key(ec_ctx1, ec_key1); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_set_key(ec_ctx2, ec_key1); EXPECT_EQ(rc, 0); /* Perform sign/verify: ctx1 -> ctx2 */ rc = zpc_ecdsa_sign(ec_ctx1, hash, hash_len, sigbuf, &sig_len); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_verify(ec_ctx2, hash, hash_len, sigbuf, sig_len); EXPECT_EQ(rc, 0); /* Perform sign/verify: ctx2 -> ctx1 */ rc = zpc_ecdsa_sign(ec_ctx2, hash, hash_len, sigbuf, &sig_len); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_verify(ec_ctx1, hash, hash_len, sigbuf, sig_len); EXPECT_EQ(rc, 0); ret: zpc_ec_key_free(&ec_key1); EXPECT_EQ(ec_key1, nullptr); zpc_ec_key_free(&ec_key2); EXPECT_EQ(ec_key2, nullptr); zpc_ecdsa_ctx_free(&ec_ctx1); EXPECT_EQ(ec_ctx1, nullptr); zpc_ecdsa_ctx_free(&ec_ctx2); EXPECT_EQ(ec_ctx2, nullptr); } TEST(ecdsa_ctx, wycheproof_kat) { int type; TESTLIB_ENV_EC_KEY_CHECK(); type = testlib_env_ec_key_type(); TESTLIB_EC_SW_CAPS_CHECK(type); if (type == ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping wycheproof_kat test. KATs cannot be performed with UV secrets."); __run_json("wycheproof/src/wycheproof/testvectors/ecdsa_webcrypto_test.json"); __run_json("wycheproof/src/wycheproof/testvectors/eddsa_test.json"); __run_json("wycheproof/src/wycheproof/testvectors/ed448_test.json"); } TEST(ecdsa_ctx, nist_kat) { int type; TESTLIB_ENV_EC_KEY_CHECK(); type = testlib_env_ec_key_type(); TESTLIB_EC_SW_CAPS_CHECK(type); if (type == ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping nist_kat test. KATs cannot be performed with UV secrets."); __run_json("nist_ecdsa.json"); __run_json("nist_eddsa.json"); } static zpc_ec_curve_t __str2curve(const char *str) { if (strcmp(str, "P-256") == 0 || strcmp(str, "secp256r1") == 0) return ZPC_EC_CURVE_P256; else if (strcmp(str, "P-384") == 0 || strcmp(str, "secp384r1") == 0) return ZPC_EC_CURVE_P384; else if (strcmp(str, "P-521") == 0 || strcmp(str, "secp521r1") == 0) return ZPC_EC_CURVE_P521; else if (strcmp(str, "ed25519") == 0 || strcmp(str, "edwards25519") == 0) return ZPC_EC_CURVE_ED25519; else if (strcmp(str, "ed448") == 0 || strcmp(str, "edwards448") == 0) return ZPC_EC_CURVE_ED448; else return ZPC_EC_CURVE_INVALID; } static void __get_ec_params_from_json(json_object *jtmp, zpc_ec_curve_t curve, u8 *priv, unsigned int *privlen, u8 *pub, unsigned int *publen, u8 *msg, unsigned int *msglen, u8 *sig, unsigned int *siglen) { json_object *jd, *jx, *jy, *jmsg, *jsig_r, *jsig_s; json_bool b; u8 *d = NULL, *x = NULL, *y = NULL, *r = NULL, *s = NULL, *m = NULL; const char *str; size_t mlen; const unsigned int curve2privlen[] = { 32, 48, 66 }; const unsigned int curve2publen[] = { 64, 96, 132 }; const unsigned int curve2siglen[] = { 64, 96, 132 }; b = json_object_object_get_ex(jtmp, "msg", &jmsg); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "d", &jd); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "x", &jx); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "y", &jy); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "sig_r", &jsig_r); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "sig_s", &jsig_s); ASSERT_TRUE(b); str = json_object_get_string(jmsg); ASSERT_NE(str, nullptr); m = testlib_hexstr2buf(str, &mlen); ASSERT_NE(m, nullptr); str = json_object_get_string(jd); ASSERT_NE(str, nullptr); d = testlib_hexstr2fixedbuf(str, curve2privlen[curve]); ASSERT_NE(d, nullptr); str = json_object_get_string(jx); ASSERT_NE(str, nullptr); x = testlib_hexstr2fixedbuf(str, curve2publen[curve] / 2); ASSERT_NE(x, nullptr); str = json_object_get_string(jy); ASSERT_NE(str, nullptr); y = testlib_hexstr2fixedbuf(str, curve2publen[curve] / 2); ASSERT_NE(y, nullptr); str = json_object_get_string(jsig_r); ASSERT_NE(str, nullptr); r = testlib_hexstr2fixedbuf(str, curve2siglen[curve] / 2); ASSERT_NE(r, nullptr); str = json_object_get_string(jsig_s); ASSERT_NE(str, nullptr); s = testlib_hexstr2fixedbuf(str, curve2siglen[curve] / 2); ASSERT_NE(s, nullptr); memcpy(priv, d, curve2privlen[curve]); memcpy(pub, x, curve2publen[curve] / 2); memcpy(pub + curve2publen[curve] / 2, y, curve2publen[curve] / 2); memcpy(sig, r, curve2siglen[curve] / 2); memcpy(sig + curve2siglen[curve] / 2, s, curve2siglen[curve] / 2); memcpy(msg, m, mlen); *privlen = curve2privlen[curve]; *publen = curve2publen[curve]; *siglen = curve2siglen[curve]; *msglen = mlen; free(d); free(m); free(x); free(y); free(r); free(s); } static void __get_ed_params_from_json(json_object *jtmp, u8 *priv, unsigned int *privlen, u8 *pub, unsigned int *publen, u8 *msg, unsigned int *msglen, u8 *sig, unsigned int *siglen) { json_object *jd, *jq, *jm, *js; json_bool b; u8 *d = NULL, *q = NULL, *s = NULL, *m = NULL; const char *str; size_t mlen = 0, dlen = 0, qlen = 0, slen = 0; b = json_object_object_get_ex(jtmp, "msg", &jm); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "priv", &jd); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "pub", &jq); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "sig", &js); ASSERT_TRUE(b); str = json_object_get_string(jm); ASSERT_NE(str, nullptr); m = testlib_hexstr2buf(str, &mlen); /* m may be null, because ED curves can sign an empty msg */ str = json_object_get_string(jd); ASSERT_NE(str, nullptr); d = testlib_hexstr2buf(str, &dlen); ASSERT_NE(d, nullptr); str = json_object_get_string(jq); ASSERT_NE(str, nullptr); q = testlib_hexstr2buf(str, &qlen); ASSERT_NE(q, nullptr); str = json_object_get_string(js); ASSERT_NE(str, nullptr); s = testlib_hexstr2buf(str, &slen); ASSERT_NE(s, nullptr); memcpy(priv, d, dlen); memcpy(pub, q, qlen); memcpy(sig, s, slen); if (mlen > 0) memcpy(msg, m, mlen); *privlen = dlen; *publen = qlen; *siglen = slen; *msglen = mlen; free(d); free(m); free(q); free(s); } static void __get_curve_from_json(json_object *jcurve, zpc_ec_curve_t *curve) { const char *curve_str; curve_str = json_object_get_string(jcurve); ASSERT_NE(curve_str, nullptr); *curve = __str2curve(curve_str); } static void __get_result_from_json(json_object *jresult, int *valid) { const char *str; *valid = 0; str = json_object_get_string(jresult); ASSERT_NE(str, nullptr); if (strcmp(str, "valid") == 0 || strcmp(str, "acceptable") == 0) *valid = 1; } /** * Get key material from json 'key' entry */ static void __get_key_from_json(json_object *jkey, zpc_ec_curve_t curve, unsigned char *pubbuf, unsigned int *publen, unsigned char *privbuf, unsigned int *privlen) { json_object *jwx, *jwy, *jsk, *jpk; json_bool b; const char *str; u8 *d = NULL, *x = NULL, *y = NULL; const unsigned int curve2publen[] = { 64, 96, 132, 32, 57 }; const unsigned int curve2privlen[] = { 32, 48, 66, 32, 57 }; *publen = 0; *privlen = 0; b = json_object_object_get_ex(jkey, "wx", &jwx); b = json_object_object_get_ex(jkey, "wy", &jwy); if (b) { /* Here we are for ecdsa_webcrypto_test.json. This json file only * contains verify tests, i.e. only public keys. */ str = json_object_get_string(jwx); ASSERT_NE(str, nullptr); if (strlen(str) > curve2publen[curve] / 2 && str[0] == '0' && str[1] == '0') { str+=2; } x = testlib_hexstr2fixedbuf(str, curve2publen[curve] / 2); ASSERT_NE(x, nullptr); str = json_object_get_string(jwy); ASSERT_NE(str, nullptr); if (strlen(str) > curve2publen[curve] / 2 && str[0] == '0' && str[1] == '0') { str+=2; } y = testlib_hexstr2fixedbuf(str, curve2publen[curve] / 2); ASSERT_NE(y, nullptr); memcpy(pubbuf, x, curve2publen[curve] / 2); memcpy(pubbuf + curve2publen[curve] / 2, y, curve2publen[curve] / 2); *publen = curve2publen[curve]; goto done; } b = json_object_object_get_ex(jkey, "pk", &jpk); b = json_object_object_get_ex(jkey, "sk", &jsk); if (b) { /* Here we are for eddsa_test.json and ed448_test.json. These two * json files contain public and private keys. */ str = json_object_get_string(jpk); ASSERT_NE(str, nullptr); y = testlib_hexstr2fixedbuf(str, curve2publen[curve]); ASSERT_NE(y, nullptr); str = json_object_get_string(jsk); ASSERT_NE(str, nullptr); d = testlib_hexstr2fixedbuf(str, curve2privlen[curve]); ASSERT_NE(d, nullptr); memcpy(pubbuf, y, curve2publen[curve]); memcpy(privbuf, d, curve2privlen[curve]); *publen = curve2publen[curve]; *privlen = curve2privlen[curve]; } done: free(d); free(x); free(y); } static void __get_bytes_from_json(json_object *jobj, unsigned char *buf, unsigned int *len) { const char *str; u8 *bytes = NULL; size_t num_bytes; *len = 0; str = json_object_get_string(jobj); ASSERT_NE(str, nullptr); bytes = testlib_hexstr2buf(str, &num_bytes); /* bytes may be NULL */ if (num_bytes > 0) { memcpy(buf, bytes, num_bytes); *len = num_bytes; } free(bytes); } static void __run_sign_verify_test(zpc_ecdsa_ctx *ec_ctx, unsigned char *msgbuf, unsigned int msglen, unsigned char *sigbuf1, unsigned int *siglen1, unsigned int privlen) { int rc; if (privlen > 0) { rc = zpc_ecdsa_sign(ec_ctx, msgbuf, msglen, sigbuf1, siglen1); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_verify(ec_ctx, msgbuf, msglen, sigbuf1, *siglen1); EXPECT_EQ(rc, 0); } } static void __run_verify_kat_test(zpc_ecdsa_ctx *ec_ctx, zpc_ec_curve_t curve, unsigned char *msgbuf, unsigned int msglen, unsigned char *sigbuf2, unsigned int siglen2, int expected_valid) { int rc; /* * Note that for p521 CPACF expects 521 bits, padded on the leftmost * significant bits with 7 zeros to form 528 bits or 66 bytes (octets). * But all considered test vectors for p521 have input hashs/msgs up to * 64 bytes, so let's use 64 bytes for the tests here. */ const unsigned int curve2msglen[] = { 32, 48, 64 }; switch (curve) { case ZPC_EC_CURVE_P256: case ZPC_EC_CURVE_P384: case ZPC_EC_CURVE_P521: rc = zpc_ecdsa_verify(ec_ctx, msgbuf, msglen, sigbuf2, siglen2); if (msglen == curve2msglen[curve]) { /* For EC curves CPACF has fixed expected hash lengths via the CPACF * parm block layout. So the actual hash length does not go into * CPACF and we can verify a test signature only if the test vector * msg length is equal to the expected CPACF hash buffer size. */ if (expected_valid) EXPECT_EQ(rc, 0); else EXPECT_EQ(rc, ZPC_ERROR_EC_SIGNATURE_INVALID); } break; case ZPC_EC_CURVE_ED25519: case ZPC_EC_CURVE_ED448: /* For ED curves the hash/msg length is an input parm to the * KDSA instruction, so we can verify any msglen */ rc = zpc_ecdsa_verify(ec_ctx, msgbuf, msglen, sigbuf2, siglen2); if (expected_valid) EXPECT_EQ(rc, 0); else EXPECT_TRUE(rc != 0); break; default: break; } } static void __run_nist_tests(json_object *jtestgroups, struct zpc_ec_key *ec_key) { size_t i, j; zpc_ec_curve_t curve; struct zpc_ecdsa_ctx *ec_ctx; json_object *jtmp, *jtests, *jcurve; json_bool b; int rc; rc = zpc_ecdsa_ctx_alloc(&ec_ctx); EXPECT_EQ(rc, 0); for (i = 0; i < (size_t)json_object_array_length(jtestgroups); i++) { jtmp = json_object_array_get_idx(jtestgroups, i); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "tests", &jtests); ASSERT_TRUE(b); for (j = 0; j < (size_t)json_object_array_length(jtests); j++) { u8 pubbuf[200] = { 0 }, privbuf[100] = { 0 }; u8 sigbuf1[200] = { 0 }, sigbuf2[200] = { 0 }, msgbuf[4096] = { 0 }; unsigned int siglen1 = sizeof(sigbuf1), siglen2 = sizeof(sigbuf2); unsigned int privlen, publen, msglen; jtmp = json_object_array_get_idx(jtests, j); ASSERT_NE(jtmp, nullptr); b = json_object_object_get_ex(jtmp, "curve", &jcurve); ASSERT_TRUE(b); __get_curve_from_json(jcurve, &curve); if (curve == ZPC_EC_CURVE_INVALID) continue; rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); switch (curve) { case ZPC_EC_CURVE_P256: case ZPC_EC_CURVE_P384: case ZPC_EC_CURVE_P521: __get_ec_params_from_json(jtmp, curve, privbuf, &privlen, pubbuf, &publen, msgbuf, &msglen, sigbuf2, &siglen1); break; case ZPC_EC_CURVE_ED25519: case ZPC_EC_CURVE_ED448: __get_ed_params_from_json(jtmp, privbuf, &privlen, pubbuf, &publen, msgbuf, &msglen, sigbuf2, &siglen1); break; default: continue; } siglen2 = siglen1; /* Import clear key from test vector */ rc = zpc_ec_key_import_clear(ec_key, pubbuf, publen, privbuf, privlen); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_set_key(ec_ctx, ec_key); EXPECT_EQ(rc, 0); /* Perform tests */ __run_sign_verify_test(ec_ctx, msgbuf, msglen, sigbuf1, &siglen1, privlen); __run_verify_kat_test(ec_ctx, curve, msgbuf, msglen, sigbuf2, siglen2, 1); /* Unset key. */ rc = zpc_ecdsa_ctx_set_key(ec_ctx, NULL); EXPECT_EQ(rc, 0); } } zpc_ecdsa_ctx_free(&ec_ctx); EXPECT_EQ(ec_ctx, nullptr); } static void __run_wycheproof_tests(json_object *jtestgroups, struct zpc_ec_key *ec_key) { json_object *jkey, *jcurve, *jtests, *jtmp, *jmsg, *jsig, *jresult; json_bool b; size_t i, j; struct zpc_ecdsa_ctx *ec_ctx; zpc_ec_curve_t curve; int valid, rc; rc = zpc_ecdsa_ctx_alloc(&ec_ctx); EXPECT_EQ(rc, 0); for (i = 0; i < (size_t)json_object_array_length(jtestgroups); i++) { u8 sigbuf1[200] = { 0 }, sigbuf2[200] = { 0 }, msgbuf[4096] = { 0 }; u8 pubbuf[200] = { 0 }, privbuf[100] = { 0 }; unsigned int siglen1 = sizeof(sigbuf1), siglen2 = sizeof(sigbuf2); unsigned int privlen, publen, msglen; jtmp = json_object_array_get_idx(jtestgroups, i); ASSERT_NE(jtmp, nullptr); /* Get 'key' entry with key material */ b = json_object_object_get_ex(jtmp, "key", &jkey); ASSERT_TRUE(b); /* Get curve from json 'key' entry */ b = json_object_object_get_ex(jkey, "curve", &jcurve); ASSERT_TRUE(b); __get_curve_from_json(jcurve, &curve); if (curve == ZPC_EC_CURVE_INVALID) continue; rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); /* Get clear key from json 'key' entry */ __get_key_from_json(jkey, curve, (unsigned char *)&pubbuf, &publen, (unsigned char *)&privbuf, &privlen); rc = zpc_ec_key_import_clear(ec_key, pubbuf, publen, privbuf, privlen); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_set_key(ec_ctx, ec_key); EXPECT_EQ(rc, 0); /* Perform tests for this key */ b = json_object_object_get_ex(jtmp, "tests", &jtests); ASSERT_TRUE(b); for (j = 0; j < (size_t)json_object_array_length(jtests); j++) { jtmp = json_object_array_get_idx(jtests, j); ASSERT_NE(jtmp, nullptr); /* Get msg and signature */ b = json_object_object_get_ex(jtmp, "msg", &jmsg); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "sig", &jsig); ASSERT_TRUE(b); b = json_object_object_get_ex(jtmp, "result", &jresult); ASSERT_TRUE(b); /* Get test params */ __get_bytes_from_json(jmsg, (unsigned char *)&msgbuf, &msglen); __get_bytes_from_json(jsig, (unsigned char *)&sigbuf2, &siglen2); __get_result_from_json(jresult, &valid); /* Perform tests */ __run_sign_verify_test(ec_ctx, msgbuf, msglen, sigbuf1, &siglen1, privlen); __run_verify_kat_test(ec_ctx, curve, msgbuf, msglen, sigbuf2, siglen2, valid); } rc = zpc_ecdsa_ctx_set_key(ec_ctx, NULL); EXPECT_EQ(rc, 0); } zpc_ecdsa_ctx_free(&ec_ctx); EXPECT_EQ(ec_ctx, nullptr); } static void __run_json(const char *json) { const char *tv = json; const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key; unsigned int flags; int rc, type; json_object *jtestgroups, *jfile; json_bool b; type = testlib_env_ec_key_type(); flags = testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); jfile = json_object_from_file(tv); ASSERT_NE(jfile, nullptr); b = json_object_object_get_ex(jfile, "testGroups", &jtestgroups); ASSERT_TRUE(b); if (strstr(json, "nist")) __run_nist_tests(jtestgroups, ec_key); else __run_wycheproof_tests(jtestgroups, ec_key); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ecdsa_ctx, rederive_protected_key) { unsigned int pubkeylen, privkeylen, msg_len, sig_len; zpc_ec_curve_t curve; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key; struct zpc_ecdsa_ctx *ec_ctx; unsigned int flags; int type, rc; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_HW_CAPS_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags = testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); const u8 *pubkey = ec_tv[curve].pubkey; const u8 *privkey = ec_tv[curve].privkey; const u8 *msg = ec_tv[curve].msg; const u8 *sig = ec_tv[curve].sig; pubkeylen = ec_tv[curve].pubkey_len; privkeylen = ec_tv[curve].privkey_len; msg_len = ec_tv[curve].msg_len; sig_len = ec_tv[curve].sig_len; rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_alloc(&ec_ctx); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); /* Import test key: creates the secure and protected key internally */ if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_import_clear(ec_key, pubkey, pubkeylen, privkey, privkeylen); EXPECT_EQ(rc, 0); } else { rc = testlib_set_ec_key_from_pvsecret(ec_key, type, curve); if (rc) goto ret; } rc = zpc_ecdsa_ctx_set_key(ec_ctx, ec_key); EXPECT_EQ(rc, 0); /* Invalidate protected key */ force_WKaVP_mismatch(ec_ctx); /* Sign: invalid protkey is re-created from secure key */ rc = zpc_ecdsa_sign(ec_ctx, msg, msg_len, buf, &sig_len); EXPECT_EQ(rc, 0); /* Verify locally created signature */ if (type != ZPC_EC_KEY_TYPE_PVSECRET) { memcpy(buf, sig, sig_len); rc = zpc_ecdsa_verify(ec_ctx, msg, msg_len, buf, sig_len); EXPECT_EQ(rc, 0); /* Verify known signature from NIST vector */ rc = zpc_ecdsa_verify(ec_ctx, msg, msg_len, sig, sig_len); EXPECT_EQ(rc, 0); } ret: zpc_ecdsa_ctx_free(&ec_ctx); EXPECT_EQ(ec_ctx, nullptr); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ecdsa_ctx, reencipher) { unsigned int pubkeylen, privkeylen, msg_len, sig_len; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key; struct zpc_ecdsa_ctx *ec_ctx; unsigned int flags; int type, rc; zpc_ec_curve_t curve; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_HW_CAPS_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags = testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); TESTLIB_EC_NEW_MK_CHECK(type, mkvp, apqns); if (type == ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping reencipher test. Not applicable for UV secrets."); const u8 *pubkey = ec_tv[curve].pubkey; const u8 *privkey = ec_tv[curve].privkey; const u8 *msg = ec_tv[curve].msg; const u8 *sig = ec_tv[curve].sig; pubkeylen = ec_tv[curve].pubkey_len; privkeylen = ec_tv[curve].privkey_len; msg_len = ec_tv[curve].msg_len; sig_len = ec_tv[curve].sig_len; rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_alloc(&ec_ctx); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_import_clear(ec_key, pubkey, pubkeylen, privkey, privkeylen); EXPECT_EQ(rc, 0); rc = zpc_ec_key_reencipher(ec_key, ZPC_EC_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&ec_key->cur, 0, sizeof(ec_key->cur)); /* destroy current secure key */ rc = zpc_ecdsa_ctx_set_key(ec_ctx, ec_key); EXPECT_EQ(rc, 0); memset(&ec_key->prot, 0, sizeof(ec_key->prot)); /* destroy cached protected key */ force_WKaVP_mismatch(ec_ctx); /* enforce WKaVP mismaych in ctx */ /* Sign: internally re-creates the secure key from new MK and re-creates * the protkey from created secure key. */ rc = zpc_ecdsa_sign(ec_ctx, msg, msg_len, buf, &sig_len); EXPECT_EQ(rc, 0); /* Verify locally created signature */ rc = zpc_ecdsa_verify(ec_ctx, msg, msg_len, buf, sig_len); EXPECT_EQ(rc, 0); /* Verify known signature from NIST vector */ rc = zpc_ecdsa_verify(ec_ctx, msg, msg_len, sig, sig_len); EXPECT_EQ(rc, 0); zpc_ecdsa_ctx_free(&ec_ctx); EXPECT_EQ(ec_ctx, nullptr); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } TEST(ecdsa_ctx, use_existing) { unsigned int pubkeylen, privkeylen, msg_len, sig_len, signature_len; unsigned char buf[4096], signature[132]; unsigned int buflen; const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key, *ec_key2; struct zpc_ecdsa_ctx *ec_ctx; unsigned int flags; int type, rc; zpc_ec_curve_t curve; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_HW_CAPS_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags = testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); TESTLIB_EC_NEW_MK_CHECK(type, mkvp, apqns); if (type == ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping use_existing test. KATs cannot be performed with UV secrets."); const u8 *pubkey = ec_tv[curve].pubkey; const u8 *privkey = ec_tv[curve].privkey; const u8 *msg = ec_tv[curve].msg; pubkeylen = ec_tv[curve].pubkey_len; privkeylen = ec_tv[curve].privkey_len; msg_len = ec_tv[curve].msg_len; sig_len = ec_tv[curve].sig_len; rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_alloc(&ec_key2); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_alloc(&ec_ctx); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); rc = zpc_ec_key_import_clear(ec_key, pubkey, pubkeylen, privkey, privkeylen); EXPECT_EQ(rc, 0); buflen = sizeof(buf); rc = zpc_ec_key_export(ec_key, buf, &buflen); EXPECT_EQ(rc, 0); /* At this point we have a valid secure key in buf. Now let's assume that * host libs are not available. The existing secure key/public key pair is * still usable even without host libs. */ rc = zpc_ec_key_set_type(ec_key2, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key2, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key2, curve); EXPECT_EQ(rc, 0); /* Import existing secure key ... */ rc = zpc_ec_key_import(ec_key2, buf, buflen); EXPECT_EQ(rc, 0); /* Add public key to key object (leaves imported secure key untouched) */ rc = zpc_ec_key_import_clear(ec_key2, pubkey, pubkeylen, NULL, 0); EXPECT_EQ(rc, 0); /* At this point the already existing secure key and the corresponding * public key are imported into ec_key2. */ rc = zpc_ecdsa_ctx_set_key(ec_ctx, ec_key2); EXPECT_EQ(rc, 0); /* Now use ec_key2 for sign/verify */ signature_len = sizeof(signature); rc = zpc_ecdsa_sign(ec_ctx, msg, msg_len, signature, &signature_len); EXPECT_EQ(rc, 0); EXPECT_EQ(sig_len, signature_len); rc = zpc_ecdsa_verify(ec_ctx, msg, msg_len, signature, signature_len); EXPECT_EQ(rc, 0); zpc_ecdsa_ctx_free(&ec_ctx); EXPECT_EQ(ec_ctx, nullptr); zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); zpc_ec_key_free(&ec_key2); EXPECT_EQ(ec_key2, nullptr); } /* * This test assumes that the tester added the clear public/private key * manually to the pvsecret list file, for example: * * 12 EC-ED25519-PRIVATE-KEY: * 0x3d5f4f95cdb1cdfc71014efa1a669fd42599a0c ... <- pvsecret ID * 0xf898c8e1ba10b2aadc787a713d70a787b ... <- clear public key * 0x3fecd5c7cb294bd89b68a5959cc ... <- clear private key * 13 EC-ED448-PRIVATE-KEY: * 0x4015944 ... * ... * * The test creates one pvsecret-type key and one CCA or EP11 type key to * compare signatures. The specified APQN(s) decide if the 2nd key is CCA or * EP11. */ TEST(ecdsa_ctx, pvsecret_kat) { unsigned char sig1[132], sig2[132], pubkey[200], msg[32]; unsigned int sig1_len = sizeof(sig1), sig2_len = sizeof(sig2); unsigned int msg_len = sizeof(msg), publen = sizeof(pubkey); const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key1, *ec_key2; struct zpc_ecdsa_ctx *ec_ctx1, *ec_ctx2; unsigned int flags; int type, type2, rc; zpc_ec_curve_t curve; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_HW_CAPS_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags = testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); TESTLIB_EC_NEW_MK_CHECK(type, mkvp, apqns); if (type != ZPC_EC_KEY_TYPE_PVSECRET) GTEST_SKIP_("Skipping pvsecret_kat test. Only applicable for UV secrets."); rc = zpc_ec_key_alloc(&ec_key1); EXPECT_EQ(rc, 0); rc = zpc_ec_key_alloc(&ec_key2); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_alloc(&ec_ctx1); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_alloc(&ec_ctx2); EXPECT_EQ(rc, 0); /* * key1 contains private key from pvsecret and public key from list file * if the tester added the clear public key to the list file. */ rc = zpc_ec_key_set_type(ec_key1, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key1, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key1, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key1, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key1, curve); EXPECT_EQ(rc, 0); rc = testlib_set_ec_key_from_pvsecret(ec_key1, type, curve); if (rc) goto ret; rc = zpc_ec_key_export_public(ec_key1, pubkey, &publen); if (rc != 0 || publen == 0) goto ret; rc = zpc_ecdsa_ctx_set_key(ec_ctx1, ec_key1); EXPECT_EQ(rc, 0); /* * key2 contains both key parts from list file if the tester added them * to the list file. We first try to create a CCA type key with the given * APQN(s), if this fails we retry with EP11. */ type2 = ZPC_EC_KEY_TYPE_CCA; while (1) { rc = zpc_ec_key_set_type(ec_key2, type2); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key2, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key2, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key2, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key2, curve); EXPECT_EQ(rc, 0); rc = testlib_set_ec_key_from_file(ec_key2, type2, curve); if (rc == ZPC_ERROR_EC_KEY_PARTS_INCONSISTENT) { type2 = ZPC_EC_KEY_TYPE_EP11; continue; } if (rc) goto ret; else break; } rc = zpc_ecdsa_ctx_set_key(ec_ctx2, ec_key2); EXPECT_EQ(rc, 0); /* Now sign with key1 and verify with both, key1 and key2 */ rc = zpc_ecdsa_sign(ec_ctx1, msg, msg_len, sig1, &sig1_len); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_verify(ec_ctx1, msg, msg_len, sig1, sig1_len); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_verify(ec_ctx2, msg, msg_len, sig1, sig1_len); EXPECT_EQ(rc, 0); /* Now sign with key2 and verify with key1 and key2 */ rc = zpc_ecdsa_sign(ec_ctx2, msg, msg_len, sig2, &sig2_len); EXPECT_EQ(rc, 0); EXPECT_TRUE(sig1_len == sig2_len); if (curve == ZPC_EC_CURVE_ED25519 || curve == ZPC_EC_CURVE_ED448) { EXPECT_TRUE(memcmp(sig1, sig2, sig1_len) == 0); } rc = zpc_ecdsa_verify(ec_ctx1, msg, msg_len, sig2, sig2_len); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_verify(ec_ctx2, msg, msg_len, sig1, sig1_len); EXPECT_EQ(rc, 0); ret: zpc_ecdsa_ctx_free(&ec_ctx1); EXPECT_EQ(ec_ctx1, nullptr); zpc_ecdsa_ctx_free(&ec_ctx2); EXPECT_EQ(ec_ctx2, nullptr); zpc_ec_key_free(&ec_key1); EXPECT_EQ(ec_key1, nullptr); zpc_ec_key_free(&ec_key2); EXPECT_EQ(ec_key2, nullptr); } static void __task(struct zpc_ec_key *ec_key) { struct zpc_ecdsa_ctx *ec_ctx; unsigned char sigbuf[200]; unsigned int msglen, siglen; int rc, i; const u8 *msg = ec_tv[ec_key->curve].msg; const u8 *sig = ec_tv[ec_key->curve].sig; msglen = ec_tv[ec_key->curve].msg_len; siglen = ec_tv[ec_key->curve].sig_len; rc = zpc_ecdsa_ctx_alloc(&ec_ctx); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_ctx_set_key(ec_ctx, ec_key); EXPECT_EQ(rc, 0); for (i = 0; i < 1000; i++) { /* Sign */ force_WKaVP_mismatch(ec_ctx); rc = zpc_ecdsa_sign(ec_ctx, msg, msglen, sigbuf, &siglen); EXPECT_EQ(rc, 0); /* All curves: Verify against created signature and known signature * from NIST test vector. We cannot specify the random-value for prime * curves, so we never get to the NIST result by signing here. */ if (ec_key->type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ecdsa_verify(ec_ctx, msg, msglen, sigbuf, siglen); EXPECT_EQ(rc, 0); rc = zpc_ecdsa_verify(ec_ctx, msg, msglen, sig, siglen); EXPECT_EQ(rc, 0); /* Edwards curves do not use a random value when signing, so we can * check if the locally created signature matches the known * signature. */ if (ec_key->curve == ZPC_EC_CURVE_ED25519 || ec_key->curve == ZPC_EC_CURVE_ED448) { EXPECT_TRUE(memcmp(sigbuf, sig, siglen) == 0); } } } zpc_ecdsa_ctx_free(&ec_ctx); EXPECT_EQ(ec_ctx, nullptr); } TEST(ecdsa_ctx, threads) { unsigned int pubkeylen, privkeylen; const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key; unsigned int flags; int type, rc, i; std::thread *t[500]; zpc_ec_curve_t curve; TESTLIB_ENV_EC_KEY_CHECK(); TESTLIB_EC_HW_CAPS_CHECK(); curve = testlib_env_ec_key_curve(); type = testlib_env_ec_key_type(); flags = testlib_env_ec_key_flags(); mkvp = testlib_env_ec_key_mkvp(); (void)testlib_env_ec_key_apqns(apqns); TESTLIB_EC_SW_CAPS_CHECK(type); TESTLIB_EC_KERNEL_CAPS_CHECK(type, mkvp, apqns); TESTLIB_EC_NEW_MK_CHECK(type, mkvp, apqns); const u8 *pubkey = ec_tv[curve].pubkey; const u8 *privkey = ec_tv[curve].privkey; pubkeylen = ec_tv[curve].pubkey_len; privkeylen = ec_tv[curve].privkey_len; rc = zpc_ec_key_alloc(&ec_key); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_type(ec_key, type); EXPECT_EQ(rc, 0); if (mkvp != NULL) { rc = zpc_ec_key_set_mkvp(ec_key, mkvp); EXPECT_EQ(rc, 0); } else { rc = zpc_ec_key_set_apqns(ec_key, apqns); EXPECT_EQ(rc, 0); } rc = zpc_ec_key_set_flags(ec_key, flags); EXPECT_EQ(rc, 0); rc = zpc_ec_key_set_curve(ec_key, curve); EXPECT_EQ(rc, 0); if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_import_clear(ec_key, pubkey, pubkeylen, privkey, privkeylen); EXPECT_EQ(rc, 0); } else { rc = testlib_set_ec_key_from_pvsecret(ec_key, type, curve); if (rc) goto ret; } for (i = 0; i < 500; i++) { t[i] = new std::thread(__task, ec_key); } /* Do something with key object while threads are working with it. */ if (type != ZPC_EC_KEY_TYPE_PVSECRET) { rc = zpc_ec_key_reencipher(ec_key, ZPC_EC_KEY_REENCIPHER_CURRENT_TO_NEW); EXPECT_EQ(rc, 0); memset(&ec_key->cur, 0, sizeof(ec_key->cur)); /* destroy current secure key */ } for (i = 0; i < 500; i++) { memset(&ec_key->prot, 0, sizeof(ec_key->prot)); /* destroy cached protected key */ usleep(1); } for (i = 0; i < 500; i++) { t[i]->join(); delete t[i]; } ret: zpc_ec_key_free(&ec_key); EXPECT_EQ(ec_key, nullptr); } libzpc-1.3.0/test/t_environment.cc000066400000000000000000000026141475140344100171610ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "gtest/gtest.h" #include "testlib.h" #include "zpc/aes_key.h" #include "zpc/ecc_key.h" #include /* * Check for invalid test environment variable values. * Unset environment variables are ignored. The corresponding tests are * skipped later. */ /* * Check environment variables for test cases * that use zpc_aes_key objects. */ TEST(environment, test_aes_key) { int size; size = testlib_env_aes_key_size(); switch(size) { case -1: /* fall-through */ case 128: /* fall-through */ case 192: /* fall-through */ case 256: /* fall-through */ break; default: ASSERT_TRUE(size == 128 || size == 192 || size == 256); break; } } /* * Check environment variables for test cases * that use zpc_ec_key objects. */ TEST(environment, test_ec_key) { int curve; curve = testlib_env_ec_key_curve(); switch(curve) { case ZPC_EC_CURVE_NOT_SET: /* fall-through */ case ZPC_EC_CURVE_P256: /* fall-through */ case ZPC_EC_CURVE_P384: /* fall-through */ case ZPC_EC_CURVE_P521: /* fall-through */ case ZPC_EC_CURVE_ED25519: /* fall-through */ case ZPC_EC_CURVE_ED448: /* fall-through */ break; default: ASSERT_TRUE(curve >= ZPC_EC_CURVE_P256 && curve <= ZPC_EC_CURVE_ED448); break; } } libzpc-1.3.0/test/t_error.cc000066400000000000000000000010511475140344100157400ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "gtest/gtest.h" #include "zpc/error.h" #include #include TEST(error, string) { const char *errstr; errstr = zpc_error_string(0); EXPECT_TRUE(strcmp(errstr, "success") == 0); errstr = zpc_error_string(-1); EXPECT_TRUE(strcmp(errstr, "undefined error code") == 0); errstr = zpc_error_string(82); EXPECT_TRUE(strcmp(errstr, "LAST") == 0); } libzpc-1.3.0/test/t_system.cc000066400000000000000000000014151475140344100161370ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "gtest/gtest.h" #include #include #include #include #include TEST(system, platform) { const union { long _; char little; } is_endian = { 1 }; EXPECT_TRUE(sizeof(char) == 1); EXPECT_TRUE(sizeof(short) == 2); EXPECT_TRUE(sizeof(int) == 4); EXPECT_TRUE(sizeof(size_t) == 8); EXPECT_TRUE(sizeof(long) == 8); EXPECT_TRUE(sizeof(long long) == 8); EXPECT_FALSE(is_endian.little); } TEST(system, dev_pkey) { int pkeyfd; EXPECT_GE(pkeyfd = open("/dev/pkey", O_RDWR), 0); if (pkeyfd >= 0) { close(pkeyfd); pkeyfd = -1; } } libzpc-1.3.0/test/t_testlib.cc000066400000000000000000000226331475140344100162660ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "gtest/gtest.h" #include "testlib.h" #include "zpc/aes_key.h" #include #include #include TEST(testlib, env_aes_key_mkvp) { const char *oldenv = NULL, *mkvp; int rc; /* Save environment. */ oldenv = getenv("ZPC_TEST_AES_KEY_MKVP"); rc = setenv("ZPC_TEST_AES_KEY_MKVP", "abcde", 1); ASSERT_EQ(rc, 0); mkvp = testlib_env_aes_key_mkvp(); EXPECT_TRUE(strcmp(mkvp, "abcde") == 0); rc = unsetenv("ZPC_TEST_AES_KEY_MKVP"); ASSERT_EQ(rc, 0); mkvp = testlib_env_aes_key_mkvp(); EXPECT_EQ(mkvp, nullptr); if (oldenv != NULL) { /* Restore environment. */ rc = setenv("ZPC_TEST_AES_KEY_MKVP", oldenv, 1); ASSERT_EQ(rc, 0); } } TEST(testlib, env_aes_key_apqns) { const char *oldenv = NULL; const char *apqns[257]; int rc; /* Save environment. */ oldenv = getenv("ZPC_TEST_AES_KEY_APQNS"); rc = setenv("ZPC_TEST_AES_KEY_APQNS", "abcde fg\nhi\tj,k \n\t, l", 1); ASSERT_EQ(rc, 0); rc = testlib_env_aes_key_apqns(apqns); EXPECT_TRUE(strcmp(apqns[0], "abcde") == 0); EXPECT_TRUE(strcmp(apqns[1], "fg") == 0); EXPECT_TRUE(strcmp(apqns[2], "hi") == 0); EXPECT_TRUE(strcmp(apqns[3], "j") == 0); EXPECT_TRUE(strcmp(apqns[4], "k") == 0); EXPECT_TRUE(strcmp(apqns[5], "l") == 0); EXPECT_EQ(apqns[6], nullptr); rc = unsetenv("ZPC_TEST_AES_KEY_APQNS"); ASSERT_EQ(rc, 0); rc = testlib_env_aes_key_apqns(apqns); EXPECT_EQ(rc, -1); if (oldenv != NULL) { /* Restore environment. */ rc = setenv("ZPC_TEST_AES_KEY_APQNS", oldenv, 1); ASSERT_EQ(rc, 0); } } TEST(testlib, env_aes_key_size) { const char *oldenv = NULL; int rc, size; size_t i; struct { const char *sizestr; const int sizeint; } kat[] = { { "", -1 }, { "abcde", -1 }, { "-2147483649", /* -max(4 byte int) - 2 = -2^31 - 1 */ -1 }, { "2147483648", /* max(4 byte int) + 1 = 2^31 */ -1 }, { "-1", -1 }, { "-0xa", -10 }, { "-0XFf", -255 }, { "-011", -9 }, { "256", 256 }, { "0xB", 11 }, { "0XfF", 255 }, { "012", 10 } }; /* Save environment. */ oldenv = getenv("ZPC_TEST_AES_KEY_SIZE"); for (i = 0; i < NMEMB(kat); i++) { rc = setenv("ZPC_TEST_AES_KEY_SIZE", kat[i].sizestr, 1); ASSERT_EQ(rc, 0); size = testlib_env_aes_key_size(); EXPECT_EQ(size, kat[i].sizeint); rc = unsetenv("ZPC_TEST_AES_KEY_SIZE"); ASSERT_EQ(rc, 0); } if (oldenv != NULL) { /* Restore environment. */ rc = setenv("ZPC_TEST_AES_KEY_SIZE", oldenv, 1); ASSERT_EQ(rc, 0); } } TEST(testlib, env_aes_key_type) { const char *oldenv = NULL; int rc, type; /* Save environment. */ oldenv = getenv("ZPC_TEST_AES_KEY_TYPE"); rc = setenv("ZPC_TEST_AES_KEY_TYPE", "abcde", 1); ASSERT_EQ(rc, 0); type = testlib_env_aes_key_type(); EXPECT_EQ(type, -1); rc = unsetenv("ZPC_TEST_AES_KEY_TYPE"); ASSERT_EQ(rc, 0); rc = setenv("ZPC_TEST_AES_KEY_TYPE", "ZPC_AES_KEY_TYPE_CCA_DATA", 1); ASSERT_EQ(rc, 0); type = testlib_env_aes_key_type(); EXPECT_EQ(type, ZPC_AES_KEY_TYPE_CCA_DATA); rc = unsetenv("ZPC_TEST_AES_KEY_TYPE"); ASSERT_EQ(rc, 0); rc = setenv("ZPC_TEST_AES_KEY_TYPE", "ZPC_AES_KEY_TYPE_CCA_CIPHER", 1); ASSERT_EQ(rc, 0); type = testlib_env_aes_key_type(); EXPECT_EQ(type, ZPC_AES_KEY_TYPE_CCA_CIPHER); rc = unsetenv("ZPC_TEST_AES_KEY_TYPE"); ASSERT_EQ(rc, 0); rc = setenv("ZPC_TEST_AES_KEY_TYPE", "ZPC_AES_KEY_TYPE_EP11", 1); ASSERT_EQ(rc, 0); type = testlib_env_aes_key_type(); EXPECT_EQ(type, ZPC_AES_KEY_TYPE_EP11); rc = unsetenv("ZPC_TEST_AES_KEY_TYPE"); ASSERT_EQ(rc, 0); rc = setenv("ZPC_TEST_AES_KEY_TYPE", "ZPC_AES_KEY_TYPE_PVSECRET", 1); ASSERT_EQ(rc, 0); type = testlib_env_aes_key_type(); EXPECT_EQ(type, ZPC_AES_KEY_TYPE_PVSECRET); rc = unsetenv("ZPC_TEST_AES_KEY_TYPE"); ASSERT_EQ(rc, 0); if (oldenv != NULL) { /* Restore environment. */ rc = setenv("ZPC_TEST_AES_KEY_TYPE", oldenv, 1); ASSERT_EQ(rc, 0); } } TEST(testlib, env_aes_key_flags) { const char *oldenv = NULL; int rc; unsigned int flags; size_t i; struct { const char *flagsstr; const unsigned int flagsint; } kat[] = { { "", 0 }, { "abcde", 0 }, { "-4294967297", /* max(4 byte uint) - 1 = -2^32 - 1 */ 0 }, { "4294967296", /* max(4 byte int) + 1 = 2^32 */ 0 }, { "-1", 0 }, { "-0xa", 0 }, { "-0XFf", 0 }, { "-011", 0 }, { "256", 256 }, { "0xB", 11 }, { "0XfF", 255 }, { "012", 10 } }; /* Save environment. */ oldenv = getenv("ZPC_TEST_AES_KEY_FLAGS"); for (i = 0; i < NMEMB(kat); i++) { rc = setenv("ZPC_TEST_AES_KEY_FLAGS", kat[i].flagsstr, 1); ASSERT_EQ(rc, 0); flags = testlib_env_aes_key_flags(); EXPECT_EQ(flags, kat[i].flagsint); rc = unsetenv("ZPC_TEST_AES_KEY_FLAGS"); ASSERT_EQ(rc, 0); } if (oldenv != NULL) { /* Restore environment. */ rc = setenv("ZPC_TEST_AES_KEY_FLAGS", oldenv, 1); ASSERT_EQ(rc, 0); } } TEST(testlib, env_ec_key_type) { const char *oldenv = NULL; int rc, type; /* Save environment. */ oldenv = getenv("ZPC_TEST_EC_KEY_TYPE"); rc = setenv("ZPC_TEST_EC_KEY_TYPE", "abcde", 1); ASSERT_EQ(rc, 0); type = testlib_env_ec_key_type(); EXPECT_EQ(type, -1); rc = unsetenv("ZPC_TEST_EC_KEY_TYPE"); ASSERT_EQ(rc, 0); rc = setenv("ZPC_TEST_EC_KEY_TYPE", "ZPC_EC_KEY_TYPE_CCA", 1); ASSERT_EQ(rc, 0); type = testlib_env_ec_key_type(); EXPECT_EQ(type, ZPC_EC_KEY_TYPE_CCA); rc = unsetenv("ZPC_TEST_EC_KEY_TYPE"); ASSERT_EQ(rc, 0); rc = setenv("ZPC_TEST_EC_KEY_TYPE", "ZPC_EC_KEY_TYPE_EP11", 1); ASSERT_EQ(rc, 0); type = testlib_env_ec_key_type(); EXPECT_EQ(type, ZPC_EC_KEY_TYPE_EP11); rc = unsetenv("ZPC_TEST_EC_KEY_TYPE"); ASSERT_EQ(rc, 0); rc = setenv("ZPC_TEST_EC_KEY_TYPE", "ZPC_EC_KEY_TYPE_PVSECRET", 1); ASSERT_EQ(rc, 0); type = testlib_env_ec_key_type(); EXPECT_EQ(type, ZPC_EC_KEY_TYPE_PVSECRET); rc = unsetenv("ZPC_TEST_EC_KEY_TYPE"); ASSERT_EQ(rc, 0); if (oldenv != NULL) { /* Restore environment. */ rc = setenv("ZPC_TEST_EC_KEY_TYPE", oldenv, 1); ASSERT_EQ(rc, 0); } } TEST(testlib, env_ec_key_curve) { const char *oldenv = NULL; int rc, curve; size_t i; struct { const char *curvestr; const int curveint; } kat[] = { { "", -2 }, { "blahblah", -1 }, { "p256", 0 }, { "p384", 1 }, { "p521", 2 }, { "ed25519", 3 }, { "ed448", 4 }, { "P256", 0 }, { "ED25519", 3 } }; /* Save environment. */ oldenv = getenv("ZPC_TEST_EC_KEY_CURVE"); for (i = 0; i < NMEMB(kat); i++) { rc = setenv("ZPC_TEST_EC_KEY_CURVE", kat[i].curvestr, 1); ASSERT_EQ(rc, 0); curve = testlib_env_ec_key_curve(); EXPECT_EQ(curve, kat[i].curveint); rc = unsetenv("ZPC_TEST_EC_KEY_CURVE"); ASSERT_EQ(rc, 0); } if (oldenv != NULL) { /* Restore environment. */ rc = setenv("ZPC_TEST_EC_KEY_CURVE", oldenv, 1); ASSERT_EQ(rc, 0); } } TEST(testlib, hexstr2buf) { const u8 buf1[] = {0xde, 0xad, 0xbe, 0xef}; const u8 buf2[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xaA, 0xbB, 0xcC, 0xdD, 0xeE, 0xfF}; u8 *buf; size_t buflen; buf = testlib_hexstr2buf(NULL, &buflen); EXPECT_EQ(buflen, (size_t)0); EXPECT_EQ(buf, nullptr); buf = testlib_hexstr2buf("", &buflen); EXPECT_EQ(buflen, (size_t)0); EXPECT_EQ(buf, nullptr); free(buf); buf = testlib_hexstr2buf("0x", &buflen); EXPECT_EQ(buflen, (size_t)0); EXPECT_EQ(buf, nullptr); free(buf); buf = testlib_hexstr2buf("0x 1", &buflen); EXPECT_EQ(buflen, (size_t)0); EXPECT_EQ(buf, nullptr); free(buf); buf = testlib_hexstr2buf("0xa", &buflen); EXPECT_EQ(buflen, (size_t)0); EXPECT_EQ(buf, nullptr); free(buf); buf = testlib_hexstr2buf("A", &buflen); EXPECT_EQ(buflen, (size_t)0); EXPECT_EQ(buf, nullptr); free(buf); buf = testlib_hexstr2buf("9a", &buflen); EXPECT_EQ(buflen, (size_t)1); ASSERT_NE(buf, nullptr); EXPECT_EQ(buf[0], 0x9a); free(buf); buf = testlib_hexstr2buf("0xBc", &buflen); EXPECT_EQ(buflen, (size_t)1); ASSERT_NE(buf, nullptr); EXPECT_EQ(buf[0], 0xBc); free(buf); buf = testlib_hexstr2buf("crypto", NULL); EXPECT_EQ(buflen, (size_t)1); EXPECT_EQ(buf, nullptr); free(buf); buf = testlib_hexstr2buf("deadbeef", &buflen); ASSERT_NE(buf, nullptr); EXPECT_EQ(buflen, (size_t)4); EXPECT_TRUE(memcmp(buf, buf1, buflen) == 0); free(buf); buf = testlib_hexstr2buf("0x0123456789aAbBcCdDeEfF", &buflen); ASSERT_NE(buf, nullptr); EXPECT_EQ(buflen, (size_t)11); EXPECT_TRUE(memcmp(buf, buf2, buflen) == 0); free(buf); buf = testlib_hexstr2buf("0123456789aAbBcCdDeEfF", &buflen); ASSERT_NE(buf, nullptr); EXPECT_EQ(buflen, (size_t)11); EXPECT_TRUE(memcmp(buf, buf2, buflen) == 0); free(buf); } TEST(testlib, buf2hexstr) { const u8 buf1[] = {0xde, 0xad, 0xbe, 0xef}; const u8 buf2[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xaA, 0xbB, 0xcC, 0xdD, 0xeE, 0xfF}; char *hexstr; hexstr = testlib_buf2hexstr(NULL, 0); EXPECT_EQ(hexstr, nullptr); free(hexstr); hexstr = testlib_buf2hexstr(NULL, 1); EXPECT_EQ(hexstr, nullptr); free(hexstr); hexstr = testlib_buf2hexstr(buf1, 0); EXPECT_EQ(hexstr, nullptr); free(hexstr); hexstr = testlib_buf2hexstr(buf1, SIZE_MAX / 2); EXPECT_EQ(hexstr, nullptr); free(hexstr); hexstr = testlib_buf2hexstr(buf1, sizeof(buf1)); ASSERT_NE(hexstr, nullptr); EXPECT_TRUE(strcmp(hexstr, "deadbeef") == 0); free(hexstr); hexstr = testlib_buf2hexstr(buf2, sizeof(buf2)); ASSERT_NE(hexstr, nullptr); EXPECT_TRUE(strcmp(hexstr, "0123456789aabbccddeeff") == 0); free(hexstr); } libzpc-1.3.0/test/testlib.cc000066400000000000000000000755211475140344100157470ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "testlib.h" #include "zpc/aes_key.h" #include "zpc/ecc_key.h" #include #include #include #include #define ENV_AES_KEY_MKVP "ZPC_TEST_AES_KEY_MKVP" #define ENV_AES_KEY_APQNS "ZPC_TEST_AES_KEY_APQNS" #define ENV_AES_KEY_SIZE "ZPC_TEST_AES_KEY_SIZE" #define ENV_AES_KEY_TYPE "ZPC_TEST_AES_KEY_TYPE" #define ENV_AES_KEY_FLAGS "ZPC_TEST_AES_KEY_FLAGS" #define ENV_EC_KEY_MKVP "ZPC_TEST_EC_KEY_MKVP" #define ENV_EC_KEY_APQNS "ZPC_TEST_EC_KEY_APQNS" #define ENV_EC_KEY_CURVE "ZPC_TEST_EC_KEY_CURVE" #define ENV_EC_KEY_TYPE "ZPC_TEST_EC_KEY_TYPE" #define ENV_EC_KEY_FLAGS "ZPC_TEST_EC_KEY_FLAGS" /* * This file must be created by the tester before running tests with key * type ZPC_AES_KEY_TYPE_PVSECRET or ZPC_EC_KEY_TYPE_PVSECRET. * The file must contain the output from the pvsecret utility list command. * The pvsecret utility is part of s390-tools. * * Example: * * # pvsecret list >pvsecret-list.out * # export ZPC_TEST_PVSECRET_LIST_FILE=pvsecret-list.out */ #define ENV_PVSECRET_LIST_FILE "ZPC_TEST_PVSECRET_LIST_FILE" static int ishexdigit(const char); static unsigned char hexdigit2byte(char); static char byte2hexdigit(unsigned char); /* * Note: array index is curve's type. * From NIST test vectors. */ const struct EC_TEST_VECTOR ec_tv[5] = { { .curve = ZPC_EC_CURVE_P256, .privkey = { 0x51, 0x9b, 0x42, 0x3d, 0x71, 0x5f, 0x8b, 0x58, 0x1f, 0x4f, 0xa8, 0xee, 0x59, 0xf4, 0x77, 0x1a, 0x5b, 0x44, 0xc8, 0x13, 0x0b, 0x4e, 0x3e, 0xac, 0xca, 0x54, 0xa5, 0x6d, 0xda, 0x72, 0xb4, 0x64 }, .privkey_len = 32, .pubkey = { 0x1c, 0xcb, 0xe9, 0x1c, 0x07, 0x5f, 0xc7, 0xf4, 0xf0, 0x33, 0xbf, 0xa2, 0x48, 0xdb, 0x8f, 0xcc, 0xd3, 0x56, 0x5d, 0xe9, 0x4b, 0xbf, 0xb1, 0x2f, 0x3c, 0x59, 0xff, 0x46, 0xc2, 0x71, 0xbf, 0x83, 0xce, 0x40, 0x14, 0xc6, 0x88, 0x11, 0xf9, 0xa2, 0x1a, 0x1f, 0xdb, 0x2c, 0x0e, 0x61, 0x13, 0xe0, 0x6d, 0xb7, 0xca, 0x93, 0xb7, 0x40, 0x4e, 0x78, 0xdc, 0x7c, 0xcd, 0x5c, 0xa8, 0x9a, 0x4c, 0xa9 }, .pubkey_len = 64, .msg = { 0x44, 0xac, 0xf6, 0xb7, 0xe3, 0x6c, 0x13, 0x42, 0xc2, 0xc5, 0x89, 0x72, 0x04, 0xfe, 0x09, 0x50, 0x4e, 0x1e, 0x2e, 0xfb, 0x1a, 0x90, 0x03, 0x77, 0xdb, 0xc4, 0xe7, 0xa6, 0xa1, 0x33, 0xec, 0x56 }, .msg_len = 32, .sig = { 0xf3, 0xac, 0x80, 0x61, 0xb5, 0x14, 0x79, 0x5b, 0x88, 0x43, 0xe3, 0xd6, 0x62, 0x95, 0x27, 0xed, 0x2a, 0xfd, 0x6b, 0x1f, 0x6a, 0x55, 0x5a, 0x7a, 0xca, 0xbb, 0x5e, 0x6f, 0x79, 0xc8, 0xc2, 0xac, 0x8b, 0xf7, 0x78, 0x19, 0xca, 0x05, 0xa6, 0xb2, 0x78, 0x6c, 0x76, 0x26, 0x2b, 0xf7, 0x37, 0x1c, 0xef, 0x97, 0xb2, 0x18, 0xe9, 0x6f, 0x17, 0x5a, 0x3c, 0xcd, 0xda, 0x2a, 0xcc, 0x05, 0x89, 0x03 }, .sig_len = 64, }, { .curve = ZPC_EC_CURVE_P384, .privkey = { 0xad, 0xca, 0x36, 0x4e, 0xf1, 0x44, 0xa2, 0x1d, 0xf6, 0x4b, 0x16, 0x36, 0x15, 0xe8, 0x34, 0x9c, 0xf7, 0x4e, 0xe9, 0xdb, 0xf7, 0x28, 0x10, 0x42, 0x15, 0xc5, 0x32, 0x07, 0x3a, 0x7f, 0x74, 0xe2, 0xf6, 0x73, 0x85, 0x77, 0x9f, 0x7f, 0x74, 0xab, 0x34, 0x4c, 0xc3, 0xc7, 0xda, 0x06, 0x1c, 0xf6 }, .privkey_len = 48, .pubkey = { 0xef, 0x94, 0x8d, 0xaa, 0xe6, 0x82, 0x42, 0x33, 0x0a, 0x73, 0x58, 0xef, 0x73, 0xf2, 0x3b, 0x56, 0xc0, 0x7e, 0x37, 0x12, 0x62, 0x66, 0xdb, 0x3f, 0xa6, 0xee, 0xa2, 0x33, 0xa0, 0x4a, 0x9b, 0x3e, 0x49, 0x15, 0x23, 0x3d, 0xd6, 0x75, 0x44, 0x27, 0xcd, 0x4b, 0x71, 0xb7, 0x58, 0x54, 0x07, 0x7d, 0x00, 0x94, 0x53, 0xef, 0x18, 0x28, 0xea, 0xff, 0x9e, 0x17, 0xc8, 0x56, 0xd4, 0xfc, 0x18, 0x95, 0xab, 0x60, 0x05, 0x13, 0x12, 0xc3, 0xe1, 0xdb, 0x1e, 0x37, 0x66, 0x56, 0x64, 0x38, 0xb2, 0x99, 0x0c, 0xbf, 0x99, 0x45, 0xc2, 0x54, 0x56, 0x19, 0xe3, 0xe0, 0x14, 0x5b, 0xc6, 0xa7, 0x90, 0x04 }, .pubkey_len = 96, .msg = { 0xf8, 0xd0, 0x17, 0x04, 0x79, 0xb2, 0xd1, 0xa8, 0xf5, 0x0c, 0x80, 0x55, 0x6e, 0x67, 0xff, 0x34, 0x55, 0x92, 0xc8, 0xb7, 0xdc, 0xda, 0x4e, 0x4f, 0x60, 0x99, 0xf9, 0x93, 0xc1, 0xa7, 0x1b, 0xff, 0x6d, 0x3b, 0x60, 0x19, 0x07, 0x15, 0xae, 0x12, 0x15, 0xa8, 0xa7, 0x59, 0xa8, 0xeb, 0x13, 0xdf }, .msg_len = 48, .sig = { 0xdd, 0xa9, 0x94, 0xb9, 0xc4, 0x28, 0xb5, 0x7e, 0x9f, 0x8b, 0xba, 0xeb, 0xba, 0x0d, 0x68, 0x2e, 0x3a, 0xac, 0x6e, 0xd8, 0x28, 0xe3, 0xa1, 0xe9, 0x9a, 0x7f, 0xc4, 0xc8, 0x04, 0xbf, 0xf8, 0xdf, 0x15, 0x11, 0x37, 0xf5, 0x39, 0xc7, 0x38, 0x9d, 0x80, 0xe2, 0x3d, 0x9f, 0x3e, 0xe4, 0x97, 0xbf, 0xa0, 0xd6, 0xb1, 0x0c, 0xef, 0xfd, 0x0e, 0x1b, 0x29, 0xcf, 0x78, 0x44, 0x76, 0xf9, 0x17, 0x3b, 0xa6, 0xec, 0xd2, 0xcf, 0xc7, 0x92, 0x97, 0x25, 0xf2, 0xd6, 0xe2, 0x4e, 0x0d, 0xb5, 0xa4, 0x72, 0x16, 0x83, 0x64, 0x0e, 0xaa, 0x2b, 0xbe, 0x15, 0x1f, 0xb5, 0x75, 0x60, 0xf9, 0xce, 0x59, 0x4b }, .sig_len = 96, }, { .curve = ZPC_EC_CURVE_P521, .privkey = { 0x01, 0xf9, 0x86, 0x96, 0x77, 0x22, 0x21, 0xe6, 0xcc, 0xcd, 0x55, 0x69, 0xed, 0x8a, 0xed, 0x3c, 0x43, 0x5e, 0xe8, 0x6a, 0x04, 0x68, 0x9c, 0x7a, 0x64, 0xd2, 0x0c, 0x30, 0xf6, 0xfe, 0x1c, 0x59, 0xcc, 0x10, 0xc6, 0xd2, 0x91, 0x02, 0x61, 0xd3, 0x0c, 0x3b, 0x96, 0x11, 0x7a, 0x66, 0x9e, 0x19, 0xcf, 0xe5, 0xb6, 0x96, 0xb6, 0x8f, 0xee, 0xac, 0xf6, 0x1f, 0x6a, 0x3d, 0xea, 0x55, 0xe6, 0xe5, 0x83, 0x7a }, .privkey_len = 66, .pubkey = { 0x00, 0x70, 0x02, 0x87, 0x2c, 0x20, 0x0e, 0x16, 0xd5, 0x7e, 0x8e, 0x53, 0xf7, 0xbc, 0xe6, 0xe9, 0xa7, 0x83, 0x2c, 0x38, 0x7f, 0x6f, 0x9c, 0x29, 0xc6, 0xb7, 0x55, 0x26, 0x26, 0x2c, 0x57, 0xbc, 0x2b, 0x56, 0xd6, 0x3e, 0x95, 0x58, 0xc5, 0x76, 0x1c, 0x1d, 0x62, 0x70, 0x83, 0x57, 0xf5, 0x86, 0xd3, 0xaa, 0xb4, 0x1c, 0x6a, 0x7c, 0xa3, 0xbf, 0x6c, 0x32, 0xd9, 0xc3, 0xca, 0x40, 0xf9, 0xa2, 0x79, 0x6a, 0x01, 0xfe, 0x3e, 0x52, 0x47, 0x2e, 0xf2, 0x24, 0xfb, 0x38, 0xd5, 0xa0, 0xa1, 0x48, 0x75, 0xb5, 0x2c, 0x2f, 0x50, 0xb8, 0x2b, 0x99, 0xee, 0xa9, 0x8d, 0x82, 0x6c, 0x77, 0xe6, 0xa9, 0xcc, 0xf7, 0x98, 0xde, 0x5f, 0xfa, 0x92, 0xa0, 0xd6, 0x59, 0x65, 0xf7, 0x40, 0xc7, 0x02, 0xa3, 0x02, 0x7b, 0xe6, 0x6b, 0x9c, 0x84, 0x4f, 0x1b, 0x2e, 0x96, 0xc1, 0x34, 0xeb, 0x3f, 0xdf, 0x3e, 0xdd, 0xdc, 0xf1, 0x1c }, .pubkey_len = 132, .msg = { 0x72, 0x30, 0x64, 0x2b, 0x79, 0xee, 0xd2, 0xfd, 0x50, 0xf1, 0x9f, 0x79, 0xf9, 0x43, 0xd6, 0x7d, 0x6e, 0xf6, 0x09, 0xec, 0x06, 0xc9, 0xad, 0xbb, 0x4b, 0x0a, 0x62, 0x12, 0x69, 0x26, 0x08, 0x0e, 0xcd, 0x47, 0x49, 0x22, 0xd1, 0xaf, 0x6c, 0x01, 0xf4, 0xc3, 0x54, 0xaf, 0xfd, 0xe0, 0x16, 0xb2, 0x84, 0xb1, 0x3d, 0xbb, 0x31, 0x22, 0x55, 0x5d, 0xea, 0x2a, 0x2e, 0x6c, 0xa2, 0xa3, 0x57, 0xdc }, .msg_len = 64, .sig = { 0x00, 0xd7, 0x32, 0xba, 0x8b, 0x3e, 0x9c, 0x9e, 0x0a, 0x49, 0x52, 0x49, 0xe1, 0x52, 0xe5, 0xbe, 0xe6, 0x9d, 0x94, 0xe9, 0xff, 0x01, 0x2d, 0x00, 0x1b, 0x14, 0x0d, 0x4b, 0x5d, 0x08, 0x2a, 0xa9, 0xdf, 0x77, 0xe1, 0x0b, 0x65, 0xf1, 0x15, 0xa5, 0x94, 0xa5, 0x01, 0x14, 0x72, 0x2d, 0xb4, 0x2f, 0xa5, 0xfb, 0xe4, 0x57, 0xc5, 0xbd, 0x05, 0xe7, 0xac, 0x7e, 0xe5, 0x10, 0xaa, 0x68, 0xfe, 0x7b, 0x1e, 0x7f, 0x01, 0x34, 0xac, 0x5e, 0x1e, 0xe3, 0x39, 0x72, 0x7d, 0xf8, 0x0c, 0x35, 0xff, 0x5b, 0x28, 0x91, 0x59, 0x6d, 0xd1, 0x4d, 0x6c, 0xfd, 0x13, 0x7b, 0xaf, 0xd5, 0x0a, 0xb9, 0x8e, 0x2c, 0x1a, 0xb4, 0x00, 0x8a, 0x0b, 0xd0, 0x35, 0x52, 0x61, 0x8d, 0x21, 0x79, 0x12, 0xa9, 0xec, 0x50, 0x2a, 0x90, 0x2f, 0x23, 0x53, 0xe7, 0x57, 0xc3, 0xb5, 0x77, 0x63, 0x09, 0xf7, 0xf2, 0xcf, 0xeb, 0xf9, 0x13, 0xe9, 0xcd }, .sig_len = 132, }, { .curve = ZPC_EC_CURVE_ED25519, .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, .sig = { 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 }, .sig_len = 64, }, { .curve = ZPC_EC_CURVE_ED448, .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, .sig = { 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 }, .sig_len = 114, }, }; const char * testlib_env_aes_key_mkvp(void) { char *env; env = getenv(ENV_AES_KEY_MKVP); return env; } const char * testlib_env_ec_key_mkvp(void) { char *env; env = getenv(ENV_EC_KEY_MKVP); return env; } int testlib_env_aes_key_apqns(const char *apqns[257]) { char *env, *tok; int i; env = getenv(ENV_AES_KEY_APQNS); if (env == NULL) return -1; i = 0; tok = strtok(env, " \t\n,"); while (tok && i < 256) { apqns[i] = tok; tok = strtok(NULL, " \t\n,"); i++; } apqns[i] = NULL; return 0; } int testlib_env_ec_key_apqns(const char *apqns[257]) { char *env, *tok; int i; env = getenv(ENV_EC_KEY_APQNS); if (env == NULL) return -1; i = 0; tok = strtok(env, " \t\n,"); while (tok && i < 256) { apqns[i] = tok; tok = strtok(NULL, " \t\n,"); i++; } apqns[i] = NULL; return 0; } int testlib_env_aes_key_size(void) { int size = -1; /* Invalid key-size. */ long sizelong = LONG_MIN; char *env = NULL, *endptr = NULL; env = getenv(ENV_AES_KEY_SIZE); if (env == NULL || env[0] == '\0') goto ret; sizelong = strtol(env, &endptr, 0); if (*endptr != '\0' || sizelong < INT_MIN || sizelong > INT_MAX) goto ret; size = (int)sizelong; ret: return size; } int testlib_env_aes_key_type(void) { int type = -1; /* Invalid key-type. */ char *env = NULL; env = getenv(ENV_AES_KEY_TYPE); if (env == NULL) goto ret; if (strcmp(env, "ZPC_AES_KEY_TYPE_CCA_DATA") == 0) type = ZPC_AES_KEY_TYPE_CCA_DATA; else if (strcmp(env, "ZPC_AES_KEY_TYPE_CCA_CIPHER") == 0) type = ZPC_AES_KEY_TYPE_CCA_CIPHER; else if (strcmp(env, "ZPC_AES_KEY_TYPE_EP11") == 0) type = ZPC_AES_KEY_TYPE_EP11; else if (strcmp(env, "ZPC_AES_KEY_TYPE_PVSECRET") == 0) type = ZPC_AES_KEY_TYPE_PVSECRET; ret: return type; } int testlib_env_ec_key_type(void) { int type = -1; /* Invalid key-type. */ char *env = NULL; env = getenv(ENV_EC_KEY_TYPE); if (env == NULL) goto ret; if (strcmp(env, "ZPC_EC_KEY_TYPE_CCA") == 0) type = ZPC_EC_KEY_TYPE_CCA; else if (strcmp(env, "ZPC_EC_KEY_TYPE_EP11") == 0) type = ZPC_EC_KEY_TYPE_EP11; else if (strcmp(env, "ZPC_EC_KEY_TYPE_PVSECRET") == 0) type = ZPC_EC_KEY_TYPE_PVSECRET; ret: return type; } unsigned int testlib_env_aes_key_flags(void) { int flags = 0; /* Default flags. */ long flagslong = LONG_MIN; char *env = NULL, *endptr = NULL; env = getenv(ENV_AES_KEY_FLAGS); if (env == NULL || env[0] == '\0') goto ret; flagslong = strtol(env, &endptr, 0); if (*endptr != '\0' || flagslong < 0 || flagslong > UINT_MAX) goto ret; flags = (unsigned int)flagslong; ret: return flags; } unsigned int testlib_env_ec_key_flags(void) { int flags = 0; /* Default flags. */ long flagslong = LONG_MIN; char *env = NULL, *endptr = NULL; env = getenv(ENV_EC_KEY_FLAGS); if (env == NULL || env[0] == '\0') goto ret; flagslong = strtol(env, &endptr, 0); if (*endptr != '\0' || flagslong < 0 || flagslong > UINT_MAX) goto ret; flags = (unsigned int)flagslong; ret: return flags; } zpc_ec_curve_t testlib_env_ec_key_curve(void) { zpc_ec_curve_t curve; char *env = NULL; size_t i; env = getenv(ENV_EC_KEY_CURVE); if (env == NULL || env[0] == '\0') { curve = ZPC_EC_CURVE_NOT_SET; goto ret; } for (i = 0; i < strlen(env); i++) env[i] = toupper(env[i]); if (strcmp(env, "P256") == 0) curve = ZPC_EC_CURVE_P256; else if (strcmp(env, "P384") == 0) curve = ZPC_EC_CURVE_P384; else if (strcmp(env, "P521") == 0) curve = ZPC_EC_CURVE_P521; else if (strcmp(env, "ED25519") == 0) curve = ZPC_EC_CURVE_ED25519; else if (strcmp(env, "ED448") == 0) curve = ZPC_EC_CURVE_ED448; else curve = ZPC_EC_CURVE_INVALID; ret: return curve; } char * testlib_env_pvsecret_list_file(void) { return getenv(ENV_PVSECRET_LIST_FILE); } unsigned char * testlib_hexstr2buf(const char *hexstr, size_t *buflen) { unsigned char *buf = NULL; const char *ptr; size_t len, i; int err = 1; if (buflen != NULL) *buflen = 0; ptr = hexstr; if (ptr == NULL) goto ret; /* Skip possible leading '0x'. */ if (strlen(ptr) > 2 && ptr[0] == '0' && ptr[1] == 'x') ptr += 2; len = strlen(ptr); if (len % 2 != 0 || len == 0) goto ret; buf = (unsigned char *)calloc(1, len / 2); if (buf == NULL) goto ret; for (i = 0; i + 1 < len; i += 2) { if (!ishexdigit(ptr[i]) || !ishexdigit(ptr[i + 1])) goto ret; buf[i / 2] = hexdigit2byte(ptr[i]) << 4; buf[i / 2] += hexdigit2byte(ptr[i + 1]); if (buflen != NULL) (*buflen)++; } err = 0; ret: if (err) { free(buf); buf = NULL; } return buf; } /** * This is a wrapper around testlib_hexstr2buf() to convert the given hexstring * into a fixed-length, right-aligned byte buffer. It's needed to correctly * convert keys and signatures from NIST tests. The routine has the same * external behavior as testlib_hexstr2buf, i.e. the calling routine must * free the returned buffer. */ unsigned char * testlib_hexstr2fixedbuf(const char *hexstr, size_t tolen) { char temp[132 + 1] = { 0 }; unsigned char *buf, *str = NULL; size_t fromlen; int err = 1; if (hexstr == NULL || tolen == 0) goto ret; /* Final length of returned str must be tolen */ buf = (unsigned char *)calloc(1, tolen); if (buf == NULL) goto ret; /* Pre-pend a leading '0' if necessary, testlib_hexstr2buf wants an * even number of digits */ if (strlen(hexstr) % 2 != 0) { temp[0] = '0'; memcpy(&temp[1], hexstr, strlen(hexstr)); } else { memcpy(&temp[0], hexstr, strlen(hexstr)); } /* Convert buffer */ str = testlib_hexstr2buf((char *)&temp, &fromlen); assert(tolen >= fromlen); /* str gets right-aligned in buf if tolen > fromlen */ memcpy(buf + tolen - fromlen, str, fromlen); err = 0; ret: free(str); if (err) { free(buf); buf = NULL; } return buf; } char * testlib_buf2hexstr(const unsigned char *buf, size_t buflen) { char *hexstr = NULL; int err = 1; size_t i; if (buf == NULL || buflen == 0) goto ret; if (buflen * 2 + 1 < buflen) goto ret; hexstr = (char *)calloc(1, buflen * 2 + 1); if (hexstr == NULL) goto ret; for (i = 0; i < buflen; i++) { hexstr[2 * i] = byte2hexdigit(buf[i] >> 4); hexstr[2 * i + 1] = byte2hexdigit(buf[i] & 0xf); } hexstr[2 * i] = '\0'; err = 0; ret: if (err) { free(hexstr); buf = 0; } return hexstr; } static int ishexdigit(const char d) { return ((d >= '0' && d <= '9') || (d >= 'A' && d <= 'F') || (d >= 'a' && d <= 'f')); } static unsigned char hexdigit2byte(char d) { const char noff = '0' - 0; const char uoff = 'A' - 10; const char loff = 'a' - 10; return (d >= 'a' ? d - loff : (d >= 'A' ? d - uoff : d - noff)); } static char byte2hexdigit(unsigned char b) { const char noff = '0' - 0; const char loff = 'a' - 10; assert((b & 0xf0) == 0); return (b >= 10 ? b + loff : b + noff); } const char *curve2string[] = { "P256", "P384", "P521", "ED25519", "ED448", }; typedef enum { EXTRACT_ID, EXTRACT_PUBKEY, EXTRACT_PRIVKEY, EXTRACT_SECRETKEY, } testkey_extract_mode_t; const char *type2string(int type) { switch (type) { case ZPC_AES_KEY_TYPE_CCA_DATA: case ZPC_AES_KEY_TYPE_CCA_CIPHER: case ZPC_EC_KEY_TYPE_CCA: return "CCA"; case ZPC_AES_KEY_TYPE_EP11: case ZPC_EC_KEY_TYPE_EP11: return "EP11"; default: return "PVSECRET"; } } /* * A key with given type must be present in the 'pvsecret list' output file * that must be created by the tester before running the tests. * Note: the strings checked here are created by the pvsecret utility. So * whenever the pvsecret utility would use different strings, this must be * adapted here. */ int pvsec_found(const char *buffer, int pvsectype) { switch (pvsectype) { case ZPC_AES_SECRET_AES_128: if (strstr(buffer, "AES-128-KEY") != NULL) return 1; break; case ZPC_AES_SECRET_AES_192: if (strstr(buffer, "AES-192-KEY") != NULL) return 1; break; case ZPC_AES_SECRET_AES_256: if (strstr(buffer, "AES-256-KEY") != NULL) return 1; break; case ZPC_EC_SECRET_ECDSA_P256: if (strstr(buffer, "EC-SECP256R1-PRIVATE-KEY") != NULL) return 1; break; case ZPC_EC_SECRET_ECDSA_P384: if (strstr(buffer, "EC-SECP384R1-PRIVATE-KEY") != NULL) return 1; break; case ZPC_EC_SECRET_ECDSA_P521: if (strstr(buffer, "EC-SECP521R1-PRIVATE-KEY") != NULL) return 1; break; case ZPC_EC_SECRET_EDDSA_ED25519: if (strstr(buffer, "EC-ED25519-PRIVATE-KEY") != NULL) return 1; break; case ZPC_EC_SECRET_EDDSA_ED448: if (strstr(buffer, "EC-ED448-PRIVATE-KEY") != NULL) return 1; break; default: break; } return 0; } /* * Convert a given hex string of the form " 0xabcde ...." into a byte array. * Note that a leading space char is expected at the beginning of the string. */ int extract_bytes(const char *buffer, unsigned char *outbuf, unsigned int *outlen) { unsigned char *sec = NULL; char *tmp; size_t seclen; int rc = 1; /* Remove leading ' 0x' and ending newline */ tmp = (char *)buffer + 3; tmp[strlen(tmp) - 1] = 0; /* Convert hex string to byte array */ sec = testlib_hexstr2buf(tmp, &seclen); if (sec != NULL && seclen > 0) { memcpy(outbuf, sec, seclen); *outlen = seclen; rc = 0; goto ret; } ret: free(sec); return rc; } /* * Extract the pvsecret ID or secret key data from a text file created with * the 'pvsecret' utility. The name of the text file must be specified via * env variable ZPC_TEST_PVSECRET_LIST_FILE. If no pvsecret of this type is * contained in the file (and thus on this system), return an error. * * The pvsecrets-list file contains AES pvsecret IDs in this form: * * 2 AES-128-KEY: * 0x8cf9659cdea52a5c9ece7446593becc58a3ac519a14d8d54297ab5a01562b7b9 * 3 AES-192-KEY: * 0x5498c4450db472397b0637f536491d11dbaee860cf47a05c6af822f0787a1aaf * 4 AES-256-KEY: * 0x7237b089a3fcdbef82404477f1f28e20d66de8c80a7dea00cd10520293eefeff * ... * * The tester may optionally add the clear secret key of a pvsecret like: * * 5 AES-128-KEY: * 0x8cf9659cdea52a5c9e ... <- secret ID * 0xbe0274e3f3b36 ... <- clear secret key * 6 AES-XTS-256-KEY: * ... * * @return 0 success, outbuf contains extracted byte array * 1 error opening list file * 2 no pvsecret found for given type */ int testlib_get_aes_data(int size, unsigned char *outbuf, unsigned int *outlen, testkey_extract_mode_t mode) { FILE *fd; const unsigned int BUF_LEN = 300; char buffer[BUF_LEN] = { 0, }; char *fn; int i, pvsectype, rc, lines_to_skip; switch (mode) { case EXTRACT_ID: lines_to_skip = 1; break; case EXTRACT_SECRETKEY: lines_to_skip = 2; break; default: return 3; /* should not occur */ } switch (size) { case 128: pvsectype = ZPC_AES_SECRET_AES_128; break; case 192: pvsectype = ZPC_AES_SECRET_AES_192; break; default: /* 256 */ pvsectype = ZPC_AES_SECRET_AES_256; break; } fn = testlib_env_pvsecret_list_file(); if (!fn) return 1; if ((fd = fopen(fn, "r")) == NULL) return 1; while (fgets(buffer, BUF_LEN, fd)) { if (pvsec_found(buffer, pvsectype)) { for (i = 0; i < lines_to_skip; i++) { if (!fgets(buffer, BUF_LEN, fd)) { /* skip to next line */ rc = 2; goto ret; } } if (extract_bytes(buffer, outbuf, outlen) == 0) { rc = 0; goto ret; } } } rc = 2; ret: fclose(fd); return rc; } int testlib_set_aes_key_from_pvsecret(struct zpc_aes_key *aes_key, int keysize) { unsigned char pvsec_id[32] = { 0, }; unsigned int id_len; size_t i; int rc; rc = testlib_get_aes_data(keysize, pvsec_id, &id_len, EXTRACT_ID); switch (rc) { case 0: rc = zpc_aes_key_import(aes_key, pvsec_id, 32); if (rc != 0) { printf("[ ERROR ] zpc_aes_key_import from 'AES-%d-KEY' pvsecret failed with rc = %d.\n", keysize, rc); printf("Tried with ID:\n"); for (i = 0; i < sizeof(pvsec_id); i++) printf("%02X%c",pvsec_id[i],((i+1)%16)?' ':'\n'); } break; case 1: printf("[ WARNING ] Could not open pvsecret list file. Probably " "ZPC_TEST_PVSECRET_LIST_FILE not set, or file does not exist.\n"); break; case 2: printf("[ WARNING ] No AES pvsecret with size %d available on this system.\n", keysize); break; } return rc; } int testlib_set_aes_key_from_file(struct zpc_aes_key *aes_key, int type, int size) { unsigned char pvsec_id[32] = { 0, }; unsigned char keybytes[256] = { 0, }; unsigned int idlen, byteslen; int rc; rc = testlib_get_aes_data(size, pvsec_id, &idlen, EXTRACT_ID); switch (rc) { case 0: break; case 1: printf("[ WARNING ] Could not open pvsecret list file. Probably " "ZPC_TEST_PVSECRET_LIST_FILE not set, or file does not exist.\n"); goto ret; case 2: printf("[ WARNING ] No AES pvsecret with size %d available on this system.\n", size); goto ret; } rc = testlib_get_aes_data(size, keybytes, &byteslen, EXTRACT_SECRETKEY); if (rc != 0) { printf("[ INFO ] Cannot obtain clear key bytes for 'AES-%d-KEY' from list file.\n", size); goto ret; } rc = zpc_aes_key_import_clear(aes_key, keybytes); if (rc != 0) { printf("[ INFO ] Cannot import clear key data for %s-type 'AES-%d-KEY' from list file, rc = %d.\n", type2string(type), size, rc); goto ret; } rc = 0; printf("[ OK ] Imported clear key data for %s-type 'AES-%d-KEY' from list file.\n", type2string(type), size); ret: return rc; } /* * Extract the pvsecret ID, public or private key data from a text file created * with the 'pvsecret' utility. The name of the text file must be specified via * env variable ZPC_TEST_EC_KEY_PVSECTYPE. If no pvsecret of this type is * contained in the file (and thus on this system), return an error. * * The pvsecrets-list file contains EC pvsecret IDs in this form: * * 9 EC-SECP384R1-PRIVATE-KEY: * 0xf972ce506dad11195af5e2f3647237752ff2a064c9ad16b133d56062242cb4d0 * 10 EC-SECP521R1-PRIVATE-KEY: * 0xc4c2acd778caafee6c184eaf99dcefb83b43197b9f6d190ffb73460ea417d944 * 11 EC-ED25519-PRIVATE-KEY: * 0x3d5f4f95cdb1cdfc71014efa1a669fd42599a0ce2000d914a409e48bccaed584 * 12 EC-ED448-PRIVATE-KEY: * 0x40159448e5203c70a9ec00f9490ae5c7d60e00bcb1bca2ed32c8b6b1224cd45a * ... * * The tester may optionally add the clear public and private key of a pvsecret * like: * * 11 EC-ED25519-PRIVATE-KEY: * 0x3d5f4f95cdb1cdfc71014efa ... <- pvsecret ID * 0xf898c8e1ba10b2aadc787a713d70a787 ... <- clear public key * 0x3fecd5c7cb294bd89b68a5959cc59d634f51fb6e8 ... <- clear private key * 12 EC-ED448-PRIVATE-KEY: * ... * * Note that for p256, p384, and p521 only uncompressed public keys can be * added and the leading compress indicator byte 0x04 must be removed. * * @return 0 success, outbuf contains 32-byte EC pvsecret ID * 1 error opening list file * 2 no pvsecret found for given type */ int testlib_get_ec_data(zpc_ec_curve_t curve, unsigned char *outbuf, unsigned int *outlen, testkey_extract_mode_t mode) { FILE *fd; const unsigned int BUF_LEN = 300; char buffer[BUF_LEN] = { 0, }; char *fn; int i, pvsectype, rc, lines_to_skip; switch (mode) { case EXTRACT_ID: lines_to_skip = 1; break; case EXTRACT_PUBKEY: lines_to_skip = 2; break; case EXTRACT_PRIVKEY: lines_to_skip = 3; break; default: return 3; /* should not occur */ } switch (curve) { case ZPC_EC_CURVE_P256: pvsectype = ZPC_EC_SECRET_ECDSA_P256; break; case ZPC_EC_CURVE_P384: pvsectype = ZPC_EC_SECRET_ECDSA_P384; break; case ZPC_EC_CURVE_P521: pvsectype = ZPC_EC_SECRET_ECDSA_P521; break; case ZPC_EC_CURVE_ED25519: pvsectype = ZPC_EC_SECRET_EDDSA_ED25519; break; default: pvsectype = ZPC_EC_SECRET_EDDSA_ED448; break; } fn = testlib_env_pvsecret_list_file(); if (!fn) return 1; if ((fd = fopen(fn, "r")) == NULL) return 1; while (fgets(buffer, BUF_LEN, fd)) { if (pvsec_found(buffer, pvsectype)) { for (i = 0; i < lines_to_skip; i++) { if (!fgets(buffer, BUF_LEN, fd)) { /* skip to next line */ rc = 2; goto ret; } } if (extract_bytes(buffer, outbuf, outlen) == 0) { rc = 0; goto ret; } } } rc = 2; ret: fclose(fd); return rc; } /* * Obtain an EC public key from a text file, first created with the 'pvsecret' * utility, related to the given pvsecret type env variable ZPC_TEST_EC_KEY_CURVE. * The tester may add an EC/Ed public key manually by inserting the public key * clear key value after the related pvsecret ID: * * 12 EC-ED25519-PRIVATE-KEY: * 0x3d5f4f95cdb1cdfc71014efa ... 2000d914a409e48bccaed584 <- secret ID * 0xf898c8e1 ...787a7170a787b40031e75a01c282195d997e1c770d47 <- pubkey value * ... * * @return 0 success, pubkey contains pubkey value and publen its byte length * 1 error opening list file * 2 no pubkey found for given pvsecret ID */ int testlib_add_ec_public_key(const char *pvsec_id, unsigned char *pubkey, unsigned int *publen) { FILE *fd; const unsigned int BUF_LEN = 300; char buffer[BUF_LEN] = { 0, }; char *fn; int rc; unsigned char *bytes; size_t bytelen; char *tmp; fn = testlib_env_pvsecret_list_file(); if (!fn) return 1; if ((fd = fopen(fn, "r")) == NULL) return 1; while (fgets(buffer, BUF_LEN, fd)) { if (strstr(buffer, "0x") != NULL) { /* Remove leading ' 0x' and ending newline */ tmp = (char *)buffer + 3; tmp[strlen(tmp) - 1] = 0; bytes = testlib_hexstr2buf(tmp, &bytelen); if (bytes != NULL && bytelen > 0 && memcmp(bytes, pvsec_id, bytelen) == 0) { if (fgets(buffer, BUF_LEN, fd)) { /* skip to next line */ if (strstr(buffer, "0x") != NULL) { if (extract_bytes(buffer, pubkey, publen) == 0) { rc = 0; goto ret; } } } } } } rc = 2; ret: fclose(fd); return rc; } int testlib_set_ec_key_from_pvsecret(struct zpc_ec_key *ec_key, int type, zpc_ec_curve_t curve) { unsigned char pvsec_id[32] = { 0, }; unsigned char pubkey[256] = { 0, }; unsigned int i, id_len, publen; int rc; rc = testlib_get_ec_data(curve, pvsec_id, &id_len, EXTRACT_ID); switch (rc) { case 0: rc = zpc_ec_key_import(ec_key, pvsec_id, id_len); if (rc != 0) { printf("[ ERROR ] zpc_ec_key_import from 'EC-%s-PRIVATE-KEY' pvsecret failed with rc = %d.\n", curve2string[curve], rc); printf("Tried with ID:\n"); for (i = 0; i < sizeof(pvsec_id); i++) printf("%02X%c",pvsec_id[i],((i+1)%16)?' ':'\n'); } else { rc = testlib_add_ec_public_key((const char *)pvsec_id, pubkey, &publen); if (rc == 0) { rc = zpc_ec_key_import_clear(ec_key, pubkey, publen, NULL, 0); if (rc == 0) { printf("[ OK ] Added clear public key for %s-type 'EC-%s-PRIVATE-KEY' from list file.\n", type2string(type), curve2string[curve]); } else { printf("[ ERROR ] Cannot import clear public key for %s-type 'EC-%s-PRIVATE-KEY' from list file, rc = %d.\n", type2string(type), curve2string[curve], rc); } } else { printf("[ INFO ] No clear public key for %s-type 'EC-%s-PRIVATE-KEY' available in list file.\n", type2string(type), curve2string[curve]); } } break; case 1: printf("[ WARNING ] Could not open pvsecret list file. Probably " "ZPC_TEST_PVSECRET_LIST_FILE not set, or file does not exist.\n"); break; case 2: printf("[ WARNING ] No EC/Ed pvsecret for curve %s available on this system.\n", curve2string[curve]); break; } return rc; } int testlib_set_ec_key_from_file(struct zpc_ec_key *ec_key, int type, zpc_ec_curve_t curve) { unsigned char pvsec_id[32] = { 0, }; unsigned char privkey[256] = { 0, }; unsigned char pubkey[256] = { 0, }; unsigned int idlen, privlen, publen; int rc; rc = testlib_get_ec_data(curve, pvsec_id, &idlen, EXTRACT_ID); switch (rc) { case 0: break; case 1: printf("[ WARNING ] Could not open pvsecret list file. Probably " "ZPC_TEST_PVSECRET_LIST_FILE not set, or file does not exist.\n"); goto ret; case 2: printf("[ WARNING ] No EC/Ed pvsecret for curve %s available on this system.\n", curve2string[curve]); goto ret; } rc = testlib_get_ec_data(curve, pubkey, &publen, EXTRACT_PUBKEY); if (rc != 0) { printf("[ INFO ] Cannot obtain clear public key bytes for 'EC-%s-PRIVATE-KEY' from list file.\n", curve2string[curve]); goto ret; } rc = testlib_get_ec_data(curve, privkey, &privlen, EXTRACT_PRIVKEY); if (rc != 0) { printf("[ INFO ] Cannot obtain clear private key bytes for 'EC-%s-PRIVATE-KEY' from list file.\n", curve2string[curve]); goto ret; } rc = zpc_ec_key_import_clear(ec_key, pubkey, publen, privkey, privlen); if (rc != 0) { printf("[ INFO ] Cannot import clear key data for %s-type 'EC-%s-PRIVATE-KEY' from list file, rc = %d.\n", type2string(type), curve2string[curve], rc); goto ret; } rc = 0; printf("[ OK ] Imported clear key data for %s-type 'EC-%s-PRIVATE-KEY' from list file, rc = %d.\n", type2string(type), curve2string[curve], rc); ret: return rc; } libzpc-1.3.0/test/testlib.h000066400000000000000000001237421475140344100156100ustar00rootroot00000000000000/* * Copyright IBM Corp. 2021 * * libzpc is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #ifndef TESTLIB_H # define TESTLIB_H # include "gtest/gtest.h" # ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ # endif # include #include "zpc/ecc_key.h" # define UNUSED(x) (void)(x) # define NMEMB(x) (sizeof(x) / sizeof(x[0])) /* * GTEST_SKIP_ assumes the caller to be the test function that is to * be skipped. So this one has to be implemented as a macro. */ # define TESTLIB_ENV_AES_KEY_CHECK() \ do { \ const char *apqns[257]; \ const char *mkvp; \ int size, type, rc; \ \ size = testlib_env_aes_key_size(); \ switch (size) { \ case 128: /* fall-through */ \ case 192: /* fall-through */ \ case 256: /* fall-through */ \ break; \ case -1: \ GTEST_SKIP_("ZPC_TEST_AES_KEY_SIZE environment variable not set."); \ break; \ default: \ GTEST_SKIP_("ZPC_TEST_AES_KEY_SIZE environment variable set to invalid key-size."); \ break; \ } \ \ type = testlib_env_aes_key_type(); \ if (type == -1) \ GTEST_SKIP_("ZPC_TEST_AES_KEY_TYPE environment variable not set."); \ \ if (type != ZPC_AES_KEY_TYPE_PVSECRET) { \ mkvp = testlib_env_aes_key_mkvp(); \ rc = testlib_env_aes_key_apqns(apqns); \ if (rc == 0 && mkvp != NULL) \ GTEST_SKIP_("Both ZPC_TEST_AES_KEY_MKVP and ZPC_TEST_AES_KEY_APQNS environment variables set."); \ if (rc != 0 && mkvp == NULL) \ GTEST_SKIP_("ZPC_TEST_AES_KEY_MKVP and ZPC_TEST_AES_KEY_APQNS environment variables unset."); \ } \ } while (0) # define TESTLIB_AES_ECB_HW_CAPS_CHECK() \ do { \ int rc; \ struct zpc_aes_ecb *ctx; \ \ rc = zpc_aes_ecb_alloc(&ctx); \ switch (rc) { \ case ZPC_ERROR_DEVPKEY: \ GTEST_SKIP_("HW_CAPS check (AES-ECB): opening /dev/pkey failed."); \ break; \ case ZPC_ERROR_HWCAPS: \ GTEST_SKIP_("HW_CAPS check (AES-ECB): no hw capabilities for AES-ECB."); \ break; \ case ZPC_ERROR_MALLOC: \ GTEST_SKIP_("HW_CAPS check (AES-ECB): cannot allocate AES ctx object."); \ break; \ default: \ zpc_aes_ecb_free(&ctx); \ break; \ } \ } while (0) # define TESTLIB_AES_CBC_HW_CAPS_CHECK() \ do { \ int rc; \ struct zpc_aes_cbc *ctx; \ \ rc = zpc_aes_cbc_alloc(&ctx); \ switch (rc) { \ case ZPC_ERROR_DEVPKEY: \ GTEST_SKIP_("HW_CAPS check (AES-CBC): opening /dev/pkey failed."); \ break; \ case ZPC_ERROR_HWCAPS: \ GTEST_SKIP_("HW_CAPS check (AES-CBC): no hw capabilities for AES-CBC."); \ break; \ case ZPC_ERROR_MALLOC: \ GTEST_SKIP_("HW_CAPS check (AES-CBC): cannot allocate AES ctx object."); \ break; \ default: \ zpc_aes_cbc_free(&ctx); \ break; \ } \ } while (0) # define TESTLIB_AES_CMAC_HW_CAPS_CHECK() \ do { \ int rc; \ struct zpc_aes_cmac *ctx; \ \ rc = zpc_aes_cmac_alloc(&ctx); \ switch (rc) { \ case ZPC_ERROR_DEVPKEY: \ GTEST_SKIP_("HW_CAPS check (AES-CMAC): opening /dev/pkey failed.");\ break; \ case ZPC_ERROR_HWCAPS: \ GTEST_SKIP_("HW_CAPS check (AES-CMAC): no hw capabilities for AES-CMAC."); \ break; \ case ZPC_ERROR_MALLOC: \ GTEST_SKIP_("HW_CAPS check (AES-CMAC): cannot allocate AES ctx object."); \ break; \ default: \ zpc_aes_cmac_free(&ctx); \ break; \ } \ } while (0) # define TESTLIB_AES_CCM_HW_CAPS_CHECK() \ do { \ int rc; \ struct zpc_aes_ccm *ctx; \ \ rc = zpc_aes_ccm_alloc(&ctx); \ switch (rc) { \ case ZPC_ERROR_DEVPKEY: \ GTEST_SKIP_("HW_CAPS check (AES-CCM): opening /dev/pkey failed."); \ break; \ case ZPC_ERROR_HWCAPS: \ GTEST_SKIP_("HW_CAPS check (AES-CCM): no hw capabilities for AES-CCM."); \ break; \ case ZPC_ERROR_MALLOC: \ GTEST_SKIP_("HW_CAPS check (AES-CCM): cannot allocate AES ctx object."); \ break; \ default: \ zpc_aes_ccm_free(&ctx); \ break; \ } \ } while (0) # define TESTLIB_AES_GCM_HW_CAPS_CHECK() \ do { \ int rc; \ struct zpc_aes_gcm *ctx; \ \ rc = zpc_aes_gcm_alloc(&ctx); \ switch (rc) { \ case ZPC_ERROR_DEVPKEY: \ GTEST_SKIP_("HW_CAPS check (AES-GCM): opening /dev/pkey failed."); \ break; \ case ZPC_ERROR_HWCAPS: \ GTEST_SKIP_("HW_CAPS check (AES-GCM): no hw capabilities for AES-GCM."); \ break; \ case ZPC_ERROR_MALLOC: \ GTEST_SKIP_("HW_CAPS check (AES-GCM): cannot allocate AES ctx object."); \ break; \ default: \ zpc_aes_gcm_free(&ctx); \ break; \ } \ } while (0) # define TESTLIB_AES_XTS_HW_CAPS_CHECK() \ do { \ int rc; \ struct zpc_aes_xts *ctx; \ \ rc = zpc_aes_xts_alloc(&ctx); \ switch (rc) { \ case ZPC_ERROR_DEVPKEY: \ GTEST_SKIP_("HW_CAPS check (AES-XTS): opening /dev/pkey failed."); \ break; \ case ZPC_ERROR_HWCAPS: \ GTEST_SKIP_("HW_CAPS check (AES-XTS): no hw capabilities for AES-XTS."); \ break; \ case ZPC_ERROR_MALLOC: \ GTEST_SKIP_("HW_CAPS check (AES-XTS): cannot allocate AES ctx object."); \ break; \ default: \ zpc_aes_xts_free(&ctx); \ break; \ } \ } while (0) # define TESTLIB_AES_XTS_KEY_SIZE_CHECK(size) \ do { \ if (size != 128 && size != 256) { \ GTEST_SKIP_("Key size check (AES-XTS): only 128 and 256 bits supported by CPACF."); \ } \ } while (0) # define TESTLIB_AES_SW_CAPS_CHECK(type) \ do { \ int rc; \ struct zpc_aes_key *aes_key; \ \ rc = zpc_aes_key_alloc(&aes_key); \ if (rc != 0) \ GTEST_SKIP_("SW_CAPS check (AES): Cannot allocate key object."); \ \ rc = zpc_aes_key_set_type(aes_key, type); \ if ((type == ZPC_AES_KEY_TYPE_CCA_DATA || \ type == ZPC_AES_KEY_TYPE_CCA_CIPHER) && \ rc == ZPC_ERROR_CCA_HOST_LIB_NOT_AVAILABLE) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("SW_CAPS check (AES): CCA host lib not available or too old."); \ } \ if (type == ZPC_AES_KEY_TYPE_EP11 && \ rc == ZPC_ERROR_EP11_HOST_LIB_NOT_AVAILABLE) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("SW_CAPS check (AES): EP11 host lib not available or too old."); \ } \ if (type == ZPC_AES_KEY_TYPE_PVSECRET && \ rc == ZPC_ERROR_UV_PVSECRETS_NOT_AVAILABLE) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("SW_CAPS check (AES): UV retrievable secrets not available."); \ } \ if (rc != 0) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("SW_CAPS check (AES): Unexpected error when setting key type."); \ } \ zpc_aes_key_free(&aes_key); \ } while (0) # define TESTLIB_AES_KERNEL_CAPS_CHECK(type) \ do { \ int rc; \ struct zpc_aes_key *aes_key; \ \ rc = zpc_aes_key_alloc(&aes_key); \ if (rc != 0) \ GTEST_SKIP_("KERNEL_CAPS check (AES): Cannot allocate key object."); \ rc = zpc_aes_key_set_type(aes_key, type); \ if (type == ZPC_AES_KEY_TYPE_PVSECRET && \ rc == ZPC_ERROR_UV_PVSECRETS_NOT_AVAILABLE) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("KERNEL_CAPS check (AES): UV retrievable secrets not supported on this system."); \ } \ if (type != ZPC_AES_KEY_TYPE_PVSECRET) { \ rc = zpc_aes_key_set_mkvp(aes_key, NULL); /* cannot fail */ \ rc = zpc_aes_key_set_size(aes_key, 128); /* cannot fail */ \ rc = zpc_aes_key_generate(aes_key); \ if (rc == ZPC_ERROR_IOCTLGENSECK2) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("KERNEL_CAPS check (AES): ioctl PKEY_GENSECK2 not supported by kernel."); \ } \ if (rc == ZPC_ERROR_IOCTLGENSECK2) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("KERNEL_CAPS check (AES): ioctl PKEY_GENSECK2 not supported by kernel."); \ } \ if (rc != 0) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("KERNEL_CAPS check (AES): Unexpected error when generating test key."); \ } \ } \ \ zpc_aes_key_free(&aes_key); \ } while (0) # define TESTLIB_AES_NEW_MK_CHECK(type,mkvp,apqns) \ do { \ int rc; \ struct zpc_aes_key *aes_key; \ \ if (type == ZPC_AES_KEY_TYPE_PVSECRET) \ break; /* silently skip check */ \ \ rc = zpc_aes_key_alloc(&aes_key); \ if (rc != 0) \ GTEST_SKIP_("NEW_MK check (AES): Cannot allocate key object."); \ \ rc = zpc_aes_key_set_type(aes_key, type); \ if ((type == ZPC_AES_KEY_TYPE_CCA_DATA || \ type == ZPC_AES_KEY_TYPE_CCA_CIPHER) && \ rc == ZPC_ERROR_CCA_HOST_LIB_NOT_AVAILABLE) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("NEW_MK check (AES): CCA host lib not available or too old."); \ } \ if (type == ZPC_AES_KEY_TYPE_EP11 && \ rc == ZPC_ERROR_EP11_HOST_LIB_NOT_AVAILABLE) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("NEW_MK check (AES): EP11 host lib not available or too old."); \ } \ if (mkvp != NULL) { \ rc = zpc_aes_key_set_mkvp(aes_key, mkvp); \ if (rc != 0) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("NEW_MK check (AES): error setting mkvp."); \ } \ } else { \ rc = zpc_aes_key_set_apqns(aes_key, apqns); \ if (rc != 0) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("NEW_MK check (AES): error setting apqns."); \ } \ } \ rc = zpc_aes_key_set_size(aes_key, 128); /* cannot fail */ \ rc = zpc_aes_key_generate(aes_key); \ if (rc != 0) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("NEW_MK check (AES): unexpected error when generating test key."); \ } \ if (type != ZPC_AES_KEY_TYPE_PVSECRET) { \ rc = zpc_aes_key_reencipher(aes_key, ZPC_AES_KEY_REENCIPHER_CURRENT_TO_NEW); \ if (rc != 0) { \ zpc_aes_key_free(&aes_key); \ GTEST_SKIP_("NEW_MK check (AES): new MK not set for this APQN/MKVP."); \ } \ } \ zpc_aes_key_free(&aes_key); \ } while (0) # define TESTLIB_ENV_EC_KEY_CHECK() \ do { \ const char *apqns[257]; \ const char *mkvp; \ int type, rc; \ int curve = testlib_env_ec_key_curve(); \ \ switch (curve) { \ case ZPC_EC_CURVE_P256: /* fall-through */ \ case ZPC_EC_CURVE_P384: /* fall-through */ \ case ZPC_EC_CURVE_P521: /* fall-through */ \ case ZPC_EC_CURVE_ED25519: /* fall-through */ \ case ZPC_EC_CURVE_ED448: /* fall-through */ \ break; \ case ZPC_EC_CURVE_INVALID: \ GTEST_SKIP_("ZPC_TEST_EC_KEY_CURVE environment variable set to invalid value."); \ break; \ default: \ GTEST_SKIP_("ZPC_TEST_EC_KEY_CURVE environment variable not set."); \ break; \ } \ \ type = testlib_env_ec_key_type(); \ if (type == -1) \ GTEST_SKIP_("ZPC_TEST_EC_KEY_TYPE environment variable not set."); \ \ if (type != ZPC_EC_KEY_TYPE_PVSECRET) { \ mkvp = testlib_env_ec_key_mkvp(); \ rc = testlib_env_ec_key_apqns(apqns); \ if (rc == 0 && mkvp != NULL) \ GTEST_SKIP_("Both ZPC_TEST_EC_KEY_MKVP and ZPC_TEST_EC_KEY_APQNS environment variables set."); \ if (rc != 0 && mkvp == NULL) \ GTEST_SKIP_("ZPC_TEST_EC_KEY_MKVP and ZPC_TEST_EC_KEY_APQNS environment variables unset."); \ } \ } while (0) # define TESTLIB_EC_HW_CAPS_CHECK() \ do { \ int rc; \ struct zpc_ecdsa_ctx *ctx; \ \ rc = zpc_ecdsa_ctx_alloc(&ctx); \ switch (rc) { \ case ZPC_ERROR_DEVPKEY: \ GTEST_SKIP_("HW_CAPS check: opening /dev/pkey failed."); \ break; \ case ZPC_ERROR_HWCAPS: \ GTEST_SKIP_("HW_CAPS check: no hw capabilities for ECDSA."); \ break; \ case ZPC_ERROR_MALLOC: \ GTEST_SKIP_("HW_CAPS check: cannot allocate ECDSA ctx object."); \ break; \ default: \ zpc_ecdsa_ctx_free(&ctx); \ break; \ } \ } while (0) # define TESTLIB_EC_SW_CAPS_CHECK(type) \ do { \ int rc; \ struct zpc_ec_key *ec_key; \ \ rc = zpc_ec_key_alloc(&ec_key); \ if (rc != 0) \ GTEST_SKIP_("SW_CAPS check (EC): Cannot allocate key object."); \ \ rc = zpc_ec_key_set_type(ec_key, type); \ if (type == ZPC_EC_KEY_TYPE_CCA && \ rc == ZPC_ERROR_CCA_HOST_LIB_NOT_AVAILABLE) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("SW_CAPS check (EC): CCA host lib not available or too old (min CCA 7.0)."); \ } \ if (type == ZPC_EC_KEY_TYPE_EP11 && \ rc == ZPC_ERROR_EP11_HOST_LIB_NOT_AVAILABLE) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("SW_CAPS check (EC): EP11 host lib not available or too old (min EP11 3.0)."); \ } \ if (type == ZPC_EC_KEY_TYPE_PVSECRET && \ rc == ZPC_ERROR_UV_PVSECRETS_NOT_AVAILABLE) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("SW_CAPS check (EC): PVSECRET support not available on this system."); \ } \ if (rc != 0) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("HW_CAPS check (EC): unexpected error when setting key type."); \ } \ zpc_ec_key_free(&ec_key); \ } while (0) # define TESTLIB_EC_KERNEL_CAPS_CHECK(type,mkvp,apqns) \ do { \ int rc; \ struct zpc_ec_key *ec_key; \ \ rc = zpc_ec_key_alloc(&ec_key); \ if (rc != 0) \ GTEST_SKIP_("KERNEL_CAPS check (EC): Cannot allocate key object."); \ \ rc = zpc_ec_key_set_mkvp(ec_key, NULL); /* cannot fail */ \ rc = zpc_ec_key_set_curve(ec_key, ZPC_EC_CURVE_P256); /* cannot fail */ \ rc = zpc_ec_key_set_type(ec_key, type); \ if (type == ZPC_EC_KEY_TYPE_PVSECRET && \ rc == ZPC_ERROR_UV_PVSECRETS_NOT_AVAILABLE) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("KERNEL_CAPS check (EC): PVSECRET support not available on this system."); \ } \ if (rc != 0) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("KERNEL_CAPS check (EC): error setting key type."); \ } \ if (mkvp != NULL) { \ rc = zpc_ec_key_set_mkvp(ec_key, mkvp); \ if (rc != 0) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("KERNEL_CAPS check (EC): error setting mkvp."); \ } \ } else { \ rc = zpc_ec_key_set_apqns(ec_key, apqns); \ switch (rc) { \ case 0: \ break; \ case ZPC_ERROR_APQNS_INVALID_VERSION: \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("KERNEL_CAPS check (EC): probably card older than CEX7."); \ default: \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("KERNEL_CAPS check (EC): error setting apqns."); \ } \ } \ if (type != ZPC_EC_KEY_TYPE_PVSECRET) { \ rc = zpc_ec_key_generate(ec_key); \ if (rc == ZPC_ERROR_IOCTLBLOB2PROTK3) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("KERNEL_CAPS check (EC): ioctl PKEY_KBLOB2PROTK3 not supported by kernel."); \ } \ if (rc != 0) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("KERNEL_CAPS check (EC): Unexpected error when generating test key."); \ } \ } \ \ zpc_ec_key_free(&ec_key); \ } while (0) /** * The reencipher tests require current and new master keys set in the * related CCA or EP11 APQNs. For CCA, also "reencipher old to current" is * supported, but currently not tested to keep tests independent of key types. * Either mkvp or apqns must be specified (not NULL) */ # define TESTLIB_EC_NEW_MK_CHECK(type,mkvp,apqns) \ do { \ int rc; \ struct zpc_ec_key *ec_key; \ \ if (type == ZPC_EC_KEY_TYPE_PVSECRET) \ break; /* silently skip check */ \ \ rc = zpc_ec_key_alloc(&ec_key); \ if (rc != 0) \ GTEST_SKIP_("NEW_MK check (EC): Cannot allocate key object."); \ \ rc = zpc_ec_key_set_type(ec_key, type); \ if (type == ZPC_EC_KEY_TYPE_CCA && \ rc == ZPC_ERROR_CCA_HOST_LIB_NOT_AVAILABLE) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("NEW_MK check (EC): CCA host lib not available or too old (min CCA 7.0)."); \ } \ if (type == ZPC_EC_KEY_TYPE_EP11 && \ rc == ZPC_ERROR_EP11_HOST_LIB_NOT_AVAILABLE) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("NEW_MK check (EC): EP11 host lib not available or too old (min EP11 3.0)."); \ } \ if (mkvp != NULL) { \ rc = zpc_ec_key_set_mkvp(ec_key, mkvp); \ if (rc != 0) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("NEW_MK check (EC): error setting mkvp."); \ } \ } else { \ rc = zpc_ec_key_set_apqns(ec_key, apqns); \ if (rc != 0) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("NEW_MK check (EC): error setting apqns."); \ } \ } \ rc = zpc_ec_key_set_curve(ec_key, ZPC_EC_CURVE_P256);/* cannot fail */ \ rc = zpc_ec_key_generate(ec_key); \ if (rc != 0) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("NEW_MK check (EC): error generating test key."); \ } \ rc = zpc_ec_key_reencipher(ec_key, ZPC_EC_KEY_REENCIPHER_CURRENT_TO_NEW); \ if (rc != 0) { \ zpc_ec_key_free(&ec_key); \ GTEST_SKIP_("NEW_MK check (EC): new MK not set for this APQN/MKVP."); \ } \ zpc_ec_key_free(&ec_key); \ } while (0) # define TESTLIB_APQN_CAPS_CHECK(apqns, mkvp, type, size, flags) \ do { \ int rc; \ struct zpc_aes_key *aes_key; \ const u8 key[32] = {0}; \ if (type == ZPC_AES_KEY_TYPE_PVSECRET) \ break; /* silently skip check */ \ rc = zpc_aes_key_alloc(&aes_key); \ if (rc != 0) \ GTEST_SKIP_("APQN_CAPS check: Cannot allocate key object."); \ rc = zpc_aes_key_set_type(aes_key, type); \ rc += zpc_aes_key_set_size(aes_key, size); \ rc += zpc_aes_key_set_flags(aes_key, flags); \ if (rc != 0) \ GTEST_SKIP_("APQN_CAPS check: Cannot set type, size, and flags."); \ if (apqns != NULL) \ rc = zpc_aes_key_set_apqns(aes_key, apqns); \ if (rc != 0) \ GTEST_SKIP_("APQN_CAPS check: Cannot set apqns."); \ if (mkvp != NULL) \ rc = zpc_aes_key_set_mkvp(aes_key, mkvp); \ if (rc != 0) \ GTEST_SKIP_("APQN_CAPS check: Cannot set mkvp."); \ rc = zpc_aes_key_import_clear(aes_key, key); \ switch (rc) { \ case ZPC_ERROR_IOCTLCLR2SECK2: \ GTEST_SKIP_("APQN_CAPS check: Cannot create a protected key, " \ "probably card older than CEX7 or no MK set."); \ default: \ break; \ } \ zpc_aes_key_free(&aes_key); \ } while (0) typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64; struct EC_TEST_VECTOR { int curve; unsigned char privkey[66]; int privkey_len; unsigned char pubkey[132]; int pubkey_len; unsigned char msg[64]; int msg_len; unsigned char sig[144]; int sig_len; }; extern const struct EC_TEST_VECTOR ec_tv[5]; const char *testlib_env_aes_key_mkvp(void); int testlib_env_aes_key_apqns(const char *[257]); void testlib_env_aes_key_check(void); int testlib_env_aes_key_size(void); int testlib_env_aes_key_type(void); unsigned int testlib_env_aes_key_flags(void); const char *testlib_env_ec_key_mkvp(void); int testlib_env_ec_key_apqns(const char *[257]); void testlib_env_ec_key_check(void); zpc_ec_curve_t testlib_env_ec_key_curve(void); int testlib_env_ec_key_type(void); unsigned int testlib_env_ec_key_flags(void); int testlib_get_aes_pvsecret_id(int keysize, unsigned char outbuf[32]); int testlib_set_aes_key_from_pvsecret(struct zpc_aes_key *aes_key, int size); int testlib_set_aes_key_from_file(struct zpc_aes_key *aes_key, int type, int size); int testlib_get_ec_pvsecret_id(zpc_ec_curve_t curve, unsigned char outbuf[32]); int testlib_set_ec_key_from_pvsecret(struct zpc_ec_key *ec_key, int type, zpc_ec_curve_t curve); int testlib_set_ec_key_from_file(struct zpc_ec_key *ec_key, int type, zpc_ec_curve_t curve); unsigned char *testlib_hexstr2buf(const char *, size_t *); unsigned char *testlib_hexstr2fixedbuf(const char *hexstr, size_t tolen); char *testlib_buf2hexstr(const unsigned char *, size_t); # ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ # endif #endif