├── .ci ├── coverity.run ├── docker-prelude.sh ├── docker.env ├── docker.run └── download-deps.sh ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .lgtm.yml ├── CHANGELOG.md ├── LICENSE ├── Makefile-fuzz.am ├── Makefile-integration.am ├── Makefile-unit.am ├── Makefile.am ├── README.md ├── bootstrap ├── codecov.yml ├── configure.ac ├── docs ├── ARCHITECTURE.md ├── BUILDING.md ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DB_UPGRADE.md ├── EAP-TLS.md ├── FAPI.md ├── FUZZING.md ├── INITIALIZING.md ├── INSTALL.md ├── INTEROPERABILITY.md ├── MAINTAINERS.md ├── OPENSSL.md ├── OPENVPN.md ├── P11.md ├── PKCS11_TOOL.md ├── README.md ├── RELEASE.md ├── SECURITY.md ├── SSH.md ├── SSH_HOSTKEYS.md ├── coding_standard_c.txt ├── illustrations │ ├── cisco_e1500_wireless_config.jpg │ ├── object_diagram_nv_objects.png │ ├── object_diagram_transient_objects.png │ ├── pkcs11_api_classification.png │ ├── policy_model_nv_objects.png │ ├── policy_model_transient_objects.png │ └── reader-slot-token-obj.png └── tpm2-pkcs11_object_auth_model.md ├── lib ├── tpm2-pkcs11.def ├── tpm2-pkcs11.map └── tpm2-pkcs11.pc.in ├── m4 └── ld-version-script.m4 ├── misc ├── formatters │ └── tpm2.0-eclipse-cdt-formatter.xml ├── p11-kit │ └── tpm2_pkcs11.module └── tpm2-pkcs11.openssl.sample.conf ├── src ├── lib │ ├── .gitignore │ ├── attrs.c │ ├── attrs.h │ ├── backend.c │ ├── backend.h │ ├── backend_esysdb.c │ ├── backend_esysdb.h │ ├── backend_fapi.c │ ├── backend_fapi.h │ ├── checks.h │ ├── db.c │ ├── db.h │ ├── debug.h │ ├── derive.c │ ├── derive.h │ ├── digest.c │ ├── digest.h │ ├── emitter.c │ ├── emitter.h │ ├── encrypt.c │ ├── encrypt.h │ ├── general.c │ ├── general.h │ ├── key.c │ ├── key.h │ ├── list.h │ ├── log.h │ ├── mech.c │ ├── mech.h │ ├── mutex.c │ ├── mutex.h │ ├── object.c │ ├── object.h │ ├── parser.c │ ├── parser.h │ ├── random.c │ ├── random.h │ ├── session.c │ ├── session.h │ ├── session_ctx.c │ ├── session_ctx.h │ ├── session_table.c │ ├── session_table.h │ ├── sign.c │ ├── sign.h │ ├── slot.c │ ├── slot.h │ ├── ssl_util.c │ ├── ssl_util.h │ ├── token.c │ ├── token.h │ ├── tpm.c │ ├── tpm.h │ ├── twist.c │ ├── twist.h │ ├── typed_memory.c │ ├── typed_memory.h │ ├── utils.c │ └── utils.h ├── pkcs11.c └── pkcs11.h ├── test ├── .gitignore ├── fake-tpm │ └── wrap_tpm.h ├── fuzz │ ├── db-take-lock.fuzz.c │ ├── db-token-label.fuzz32.c │ ├── init-pin.fuzz.c │ ├── init-token-label.fuzz32.c │ ├── init-token-sopin.fuzz.c │ ├── scripts │ │ └── fuzz-runner.sh │ ├── set-pin.fuzz.c │ ├── utils-ctx-unwrap-objauth.c │ └── yaml-parser.fuzz.c ├── integration │ ├── .gitignore │ ├── PKCS11JavaTests.java │ ├── fixtures │ │ ├── client.cnf │ │ ├── hmac.hex.key │ │ ├── ossl-req-ca.cnf │ │ ├── ossl-req-cert.cnf │ │ ├── ossl.cnf │ │ ├── smimeextensions │ │ ├── tss2engine.cnf │ │ └── xpextensions │ ├── largebin.h │ ├── nss-tests.sh │ ├── openssl.sh │ ├── p11-tool-fapi.sh.fapi │ ├── p11-tool.sh.nosetup │ ├── pkcs-crypt.int.c │ ├── pkcs-ecdh.int.c │ ├── pkcs-find-objects.int.c │ ├── pkcs-get-attribute-value.int.c │ ├── pkcs-get-mechanism.int.c │ ├── pkcs-initialize-finalize.int.c │ ├── pkcs-keygen.int.c │ ├── pkcs-lockout.int.c │ ├── pkcs-login-logout.int.c │ ├── pkcs-misc.int.c │ ├── pkcs-session-state.c │ ├── pkcs-sign-verify.int.c │ ├── pkcs11-dbup.sh.nosetup │ ├── pkcs11-javarunner.sh.java │ ├── pkcs11-tool-init-fapi.sh.fapi │ ├── pkcs11-tool-init.sh.nosetup │ ├── pkcs11-tool.sh │ ├── ptool-link-persistent.sh.nosetup │ ├── ptool-link.sh.nosetup │ ├── python-pkcs11.sh │ ├── scripts │ │ ├── create_pkcs_store.sh │ │ ├── helpers.sh │ │ ├── int-test-funcs.sh │ │ └── int-test-setup.sh │ ├── test.c │ ├── test.h │ └── tls-tests.sh └── unit │ ├── test_attr.c │ ├── test_db.c │ ├── test_log.c │ ├── test_parser.c │ ├── test_twist.c │ └── test_utils.c └── tools ├── .gitignore ├── setup.py ├── tpm2_pkcs11 ├── __init__.py ├── command.py ├── commandlets_keys.py ├── commandlets_store.py ├── commandlets_token.py ├── db.py ├── objects.py ├── pkcs11t.py ├── tpm2.py ├── tpm2_ptool.py └── utils.py ├── tpm2_ptool └── tpm2_ptool.py /.ci/coverity.run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | 4 | set -eo pipefail 5 | 6 | echo "PROJECT=$PROJECT" 7 | 8 | if [ -z "$COVERITY_SCAN_TOKEN" ]; then 9 | echo "coverity.run invoked without COVERITY_SCAN_TOKEN set...exiting!" 10 | exit 1 11 | fi 12 | 13 | if [ -z "$COVERITY_SUBMISSION_EMAIL" ]; then 14 | echo "coverity.run invoked without COVERITY_SUBMISSION_EMAIL set...exiting!" 15 | exit 1 16 | fi 17 | 18 | # Sanity check, this should only be executing on the coverity_scan branch 19 | if [[ "$REPO_BRANCH" != *coverity_scan ]]; then 20 | echo "coverity.run invoked for non-coverity branch $REPO_BRANCH...exiting!" 21 | exit 1 22 | fi 23 | 24 | if [[ "$CC" == clang* ]]; then 25 | echo "Coverity scan branch detected, not running with clang...exiting!" 26 | exit 1 27 | fi 28 | 29 | # branch is coverity_scan 30 | echo "Running coverity build" 31 | 32 | # ensure coverity_scan tool is available to the container 33 | # We cannot package these in the docker image, as we would be distributing their software 34 | # for folks not coupled to our COVERITY_SCAN_TOKEN. 35 | if [ ! -f "$(pwd)/cov-analysis/bin/cov-build" ]; then 36 | curl --data-urlencode "project=$PROJECT" \ 37 | --data-urlencode "token=$COVERITY_SCAN_TOKEN" \ 38 | "https://scan.coverity.com/download/linux64" -o coverity_tool.tgz 39 | 40 | stat coverity_tool.tgz 41 | 42 | curl --data-urlencode "project=$PROJECT" \ 43 | --data-urlencode "token=$COVERITY_SCAN_TOKEN" \ 44 | --data-urlencode "md5=1" \ 45 | "https://scan.coverity.com/download/linux64" -o coverity_tool.md5 46 | 47 | stat coverity_tool.md5 48 | cat coverity_tool.md5 49 | md5sum coverity_tool.tgz 50 | echo "$(cat coverity_tool.md5)" coverity_tool.tgz | md5sum -c 51 | 52 | echo "unpacking cov-analysis" 53 | tar -xf coverity_tool.tgz 54 | mv cov-analysis-* cov-analysis 55 | fi 56 | 57 | export PATH=$PATH:$(pwd)/cov-analysis/bin 58 | 59 | echo "Which cov-build: $(which cov-build)" 60 | 61 | pushd "$DOCKER_BUILD_DIR" 62 | 63 | source ".ci/docker-prelude.sh" 64 | 65 | echo "Performing build with Coverity Scan" 66 | rm -rf cov-int 67 | ./bootstrap && ./configure --enable-debug && make clean 68 | cov-build --dir $DOCKER_BUILD_DIR/cov-int make -j $(nproc) 69 | 70 | echo "Collecting Coverity data for submission" 71 | rm -fr README 72 | AUTHOR="$(git log -1 $HEAD --pretty="%aN")" 73 | AUTHOR_EMAIL="$(git log -1 $HEAD --pretty="%aE")" 74 | VERSION="$(git rev-parse HEAD)" 75 | echo "Name: $AUTHOR" >> README 76 | echo "Email: $AUTHOR_EMAIL" >> README 77 | echo "Project: tpm2-pkcs11" >> README 78 | echo "Build-Version: $VERSION" >> README 79 | echo "Description: $REPO_NAME $REPO_BRANCH" >> README 80 | echo "Submitted-by: tpm2-pkcs11 CI" >> README 81 | echo "---README---" 82 | cat README 83 | echo "---EOF---" 84 | 85 | rm -f tpm2-pkcs11-scan.tgz 86 | tar -czf tpm2-pkcs11-scan.tgz README cov-int 87 | 88 | rm -rf README cov-int 89 | 90 | # upload the results 91 | echo "Testing for scan results..." 92 | scan_file=$(stat --printf='%n' tpm2-*-scan.tgz) 93 | 94 | echo "Submitting data to Coverity" 95 | curl --form token="$COVERITY_SCAN_TOKEN" \ 96 | --form email="$COVERITY_SUBMISSION_EMAIL" \ 97 | --form project="$PROJECT" \ 98 | --form file=@"$scan_file" \ 99 | --form version="$VERSION" \ 100 | --form description="$REPO_NAME $REPO_BRANCH" \ 101 | "https://scan.coverity.com/builds?project=$PROJECT" 102 | 103 | rm -rf tpm2-*-scan.tgz 104 | 105 | popd 106 | 107 | exit 0 108 | -------------------------------------------------------------------------------- /.ci/docker-prelude.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | 4 | # all command failures are fatal 5 | set -e 6 | 7 | WORKSPACE=`dirname $DOCKER_BUILD_DIR` 8 | 9 | echo "Workspace: $WORKSPACE" 10 | 11 | source $DOCKER_BUILD_DIR/.ci/download-deps.sh 12 | 13 | get_deps "$WORKSPACE" 14 | 15 | export LD_LIBRARY_PATH=/usr/local/lib/ 16 | 17 | # Unfortunately, p11tool unlearned the option for $HOME/.config/pkcs11/modules 18 | # This is true for Fedora 30 container and upstream 19 | # Thus we have to define it system-wide in this container 20 | if [ ! -e /etc/pkcs11/modules/tpm2_pkcs11.module ]; then 21 | echo "Creating /etc/pkcs11/modules/tpm2_pkcs11.module" 22 | mkdir -p /etc/pkcs11/modules || true 23 | echo "module: $DOCKER_BUILD_DIR/build/src/.libs/libtpm2_pkcs11.so" \ 24 | >/etc/pkcs11/modules/tpm2_pkcs11.module 25 | fi 26 | 27 | echo "echo changing to $DOCKER_BUILD_DIR" 28 | # Change to the docker build dir 29 | cd $DOCKER_BUILD_DIR 30 | 31 | git config --global --add safe.directory "$DOCKER_BUILD_DIR" 32 | -------------------------------------------------------------------------------- /.ci/docker.env: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | 4 | DOCKER_BUILD_DIR=/workspace/tpm2-pkcs11 5 | 6 | CC 7 | 8 | COVERITY_SCAN_TOKEN 9 | COVERITY_SUBMISSION_EMAIL 10 | 11 | PROJECT 12 | 13 | REPO_BRANCH 14 | REPO_NAME 15 | 16 | PYTHON_INTERPRETER 17 | ENABLE_COVERAGE 18 | ENABLE_FUZZING 19 | DOCKER_IMAGE 20 | -------------------------------------------------------------------------------- /.ci/docker.run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | 4 | set -e 5 | 6 | source $DOCKER_BUILD_DIR/.ci/docker-prelude.sh 7 | 8 | # export ptool location 9 | export PATH=$PATH:"$DOCKER_BUILD_DIR"/tools 10 | 11 | # Do not run tests when building on coverity_scan branch 12 | if [ "${COVERITY_SCAN_BRANCH}" == 1 ]; then 13 | echo "Coverity scan branch detected, not running build nor tests...exiting!" 14 | exit 0 15 | fi 16 | 17 | if [ "$ENABLE_FUZZING" == "true" ]; then 18 | echo "Enabling fuzz build" 19 | ./bootstrap 20 | ./configure --enable-fuzzing --enable-debug 21 | make -j4 check 22 | exit 0 23 | fi 24 | 25 | # If it's clang, enable asan 26 | if [[ "$CC" == clang* ]]; then 27 | echo "Detecting clang, enable asan" 28 | config_flags="--enable-asan" 29 | export ASAN_ENABLED=true 30 | echo "Exported ASAN_ENABLED=$ASAN_ENABLED" 31 | # To get line numbers set up the asan symbolizer 32 | clang_version=`$CC --version | head -n 1 | cut -d\ -f 3-3 | cut -d\. -f 1-2` 33 | # Sometimes the version string has an Ubuntu on the front of it and the field 34 | # location changes 35 | if [ $clang_version == "version" ]; then 36 | clang_version=`$CC --version | head -n 1 | cut -d\ -f 4-4 | cut -d\. -f 1-2` 37 | fi 38 | echo "Detected clang version: $clang_version" 39 | ASAN_SYMBOLIZER_PATH="/usr/lib/llvm-$clang_version/bin/llvm-symbolizer" 40 | if [ -e "$ASAN_SYMBOLIZER_PATH" ]; then 41 | export ASAN_SYMBOLIZER_PATH 42 | echo "Exported ASAN_SYMBOLIZER_PATH=$ASAN_SYMBOLIZER_PATH" 43 | else 44 | echo "No llvm symbolizer found at: $ASAN_SYMBOLIZER_PATH" 45 | unset ASAN_SYMBOLIZER_PATH 46 | fi 47 | # clang, you fickle beast, under version 9 I know you don't like building in the CRT 48 | # for things like __builtin_mul (undefined references to __muloti4) 49 | major_ver=$(echo $clang_version | cut -d'.' -f 1-1) 50 | if [ "$major_ver" -lt 9 ]; then 51 | echo "Detecting clang less than version 9, enabling --enable-debug --disable-overflow" 52 | config_flags="$config_flags --enable-debug --disable-overflow" 53 | echo "config_flags: $config_flags" 54 | fi 55 | else 56 | echo "Enabling Code Coverage" 57 | config_flags="--disable-hardening --enable-code-coverage" 58 | fi 59 | 60 | # Bootstrap the project 61 | ./bootstrap 62 | 63 | # clang and gcc can have features enabled in the config_flags that 64 | # avoid error checking or cause make distcheck to fail. So run a 65 | # pure check with gcc before adding those flags. 66 | if [[ "$CC" != clang* ]]; then 67 | ./configure --enable-esapi-session-manage-flags --disable-fapi --enable-unit --enable-integration 68 | make distcheck TESTS= 69 | make distclean 70 | fi 71 | 72 | # Make a build variant directory and change to it 73 | rm -rf ./build 74 | mkdir ./build 75 | pushd ./build 76 | 77 | # Run scan-build for gcc only. 78 | # Scan-build does not work with clang because of asan linking errors. 79 | if [[ "$CC" != clang* ]]; then 80 | scan-build ../configure --enable-unit --enable-integration --enable-debug=yes $config_flags 81 | scan-build --status-bugs make -j$(nproc) 82 | 83 | # scan-build causes test_tpm2_session to fail, so 84 | # rebuild after running scan-build. 85 | fi 86 | 87 | ../configure --enable-unit --enable-integration --enable-esapi-session-manage-flags --enable-fapi $config_flags 88 | make -j$(nproc) 89 | make -j check 90 | 91 | if [[ "$ENABLE_COVERAGE" == "true" ]]; then 92 | bash <(curl -s https://codecov.io/bash) 93 | fi 94 | 95 | popd 96 | 97 | exit 0 98 | -------------------------------------------------------------------------------- /.ci/download-deps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | 4 | function get_deps() { 5 | 6 | source "${DOCKER_BUILD_DIR}/test/integration/scripts/helpers.sh" 7 | check_openssl_version 8 | if [ "$OSSL3_DETECTED" -eq "1" ]; then 9 | engine_pkg="tpm2-openssl" 10 | engine_flags="" 11 | engine_version="master" 12 | tpm2_tss_version="3.2.0" 13 | else 14 | engine_pkg="tpm2-tss-engine" 15 | engine_flags="--enable-tctienvvar" 16 | engine_version="v1.1.0" 17 | tpm2_tss_version="3.0.0" 18 | fi 19 | 20 | # The list order is important and thus we can't use the keys of the dictionary as order is not preserved. 21 | local github_deps=("tpm2-tss" "tpm2-abrmd" "tpm2-tools" "${engine_pkg}") 22 | declare -A local config_flags=( ["tpm2-tss"]="--disable-doxygen-doc --enable-debug" ["tpm2-abrmd"]="--enable-debug" ["tpm2-tools"]="--disable-hardening --enable-debug" ["${engine_pkg}"]="${engine_flags}") 23 | declare -A local versions=( ["tpm2-tss"]="${tpm2_tss_version}" ["tpm2-abrmd"]="2.3.3" ["tpm2-tools"]="5.2" ["${engine_pkg}"]="${engine_version}") 24 | 25 | echo "pwd starting: `pwd`" 26 | pushd "$1" 27 | 28 | for p in ${github_deps[@]}; do 29 | configure_flags=${config_flags[$p]} 30 | echo "project: $p" 31 | echo "conf-flags: $configure_flags" 32 | if [ -d "$p" ]; then 33 | echo "Skipping project "$p", already downloaded" 34 | continue 35 | fi 36 | v=${versions[$p]} 37 | git clone --depth 1 --branch $v "https://github.com/tpm2-software/$p.git" 38 | 39 | pushd "$p" 40 | 41 | ./bootstrap 42 | ./configure $configure_flags 43 | make -j$(nproc) install 44 | 45 | # leave the git clone directory 46 | popd 47 | 48 | done; 49 | 50 | # install tpm2-pytss package 51 | # older versions of clang cannot build the wheel, gcc is always present, use it. 52 | OLD_CC="$CC" 53 | CC=gcc 54 | pip install 'git+https://github.com/tpm2-software/tpm2-pytss.git' 55 | CC="$OLD_CC" 56 | 57 | # leave the download location directory 58 | popd 59 | echo "pwd done: `pwd`" 60 | 61 | } 62 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | [push, pull_request] 4 | jobs: 5 | generic-build-test: 6 | runs-on: ubuntu-latest 7 | if: "!contains(github.ref, 'coverity_scan')" 8 | strategy: 9 | matrix: 10 | docker_image: [ ubuntu-18.04, ubuntu-20.04, fedora-30, opensuse-leap, ubuntu-22.04] 11 | compiler: [gcc, clang] 12 | exclude: 13 | - docker_image: ubuntu-22.04 14 | compiler: clang 15 | steps: 16 | - name: Check out repository 17 | uses: actions/checkout@v2 18 | with: 19 | fetch-depth: 0 20 | - name: Launch Action 21 | uses: 22 | tpm2-software/ci/runCI@main 23 | with: 24 | PROJECT_NAME: ${{ github.event.repository.name }} 25 | DOCKER_IMAGE: ${{ matrix.docker_image }} 26 | CC: ${{ matrix.compiler }} 27 | - name: failure 28 | if: ${{ failure() }} 29 | run: cat build/test-suite.log || true 30 | coverage-test: 31 | runs-on: ubuntu-latest 32 | if: "!contains(github.ref, 'coverity_scan')" 33 | steps: 34 | - name: Check out repository 35 | uses: actions/checkout@v2 36 | with: 37 | fetch-depth: 0 38 | - name: Launch Action 39 | uses: 40 | tpm2-software/ci/runCI@main 41 | with: 42 | ENABLE_COVERAGE: true 43 | DOCKER_IMAGE: ubuntu-18.04 44 | CC: gcc 45 | PROJECT_NAME: ${{ github.event.repository.name }} 46 | - name: failure 47 | if: ${{ failure() }} 48 | run: cat build/test-suite.log || true 49 | fuzzing-test: 50 | runs-on: ubuntu-latest 51 | if: "!contains(github.ref, 'coverity_scan')" 52 | steps: 53 | - name: Check out repository 54 | uses: actions/checkout@v2 55 | with: 56 | fetch-depth: 0 57 | - name: Launch Action 58 | uses: 59 | tpm2-software/ci/runCI@main 60 | with: 61 | ENABLE_FUZZING: true 62 | DOCKER_IMAGE: fedora-30 63 | CC: clang 64 | PROJECT_NAME: ${{ github.event.repository.name }} 65 | - name: failure 66 | if: ${{ failure() }} 67 | run: cat build/test-suite.log || true 68 | coverity-test: 69 | runs-on: ubuntu-latest 70 | if: contains(github.ref, 'coverity_scan') 71 | steps: 72 | - name: Check out repository 73 | uses: actions/checkout@v2 74 | with: 75 | fetch-depth: 0 76 | - name: Launch Action 77 | uses: 78 | tpm2-software/ci/coverityScan@main 79 | with: 80 | PROJECT_NAME: ${{ github.event.repository.name }} 81 | REPO_BRANCH: ${{ github.ref }} 82 | REPO_NAME: ${{ github.repository }} 83 | ENABLE_COVERITY: true 84 | DOCKER_IMAGE: ubuntu-18.04 85 | CC: gcc 86 | COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} 87 | COVERITY_SUBMISSION_EMAIL: william.c.roberts@gmail.com 88 | - name: failure 89 | if: ${{ failure() }} 90 | run: cat build/test-suite.log || true 91 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: CC0-1.0 2 | # Object files 3 | *.o 4 | *.ko 5 | *.obj 6 | *.elf 7 | 8 | # Precompiled Headers 9 | *.gch 10 | *.pch 11 | 12 | # Libraries 13 | *.lib 14 | *.a 15 | *.la 16 | *.lo 17 | 18 | # Shared objects (inc. Windows DLLs) 19 | *.dll 20 | *.so 21 | *.so.* 22 | *.dylib 23 | 24 | # Executables 25 | *.exe 26 | *.out 27 | *.app 28 | *.i*86 29 | *.x86_64 30 | *.hex 31 | 32 | # Debug files 33 | *.dSYM/ 34 | *.su 35 | 36 | # Automake 37 | Makefile.in 38 | aclocal.m4 39 | aminclude_static.am 40 | autom4te.cache 41 | compile 42 | config.guess 43 | config.sub 44 | configure 45 | depcomp 46 | install-sh 47 | ltmain.sh 48 | missing 49 | Makefile 50 | config.log 51 | config.status 52 | libtool 53 | .deps 54 | .dirstamp 55 | .libs 56 | *.gz 57 | 58 | # Generated 59 | src_vars.mk 60 | AUTHORS 61 | *.pc 62 | 63 | # Test 64 | test-driver 65 | test-suite.log 66 | test_attr 67 | test_parser 68 | test_log 69 | 70 | # Git 71 | *.orig 72 | *.diff 73 | *.patch 74 | 75 | # Tmp 76 | *.ctx 77 | 78 | nbproject/ 79 | build/ 80 | m4/* 81 | !m4/ld-version-script.m4 82 | 83 | # Java class files 84 | *.class 85 | *.stamp 86 | 87 | # fuzz logs 88 | fuzz-*.log 89 | 90 | # Fuzz Executables 91 | test/fuzz/*.fuzz 92 | test/fuzz/*.fuzz32 93 | 94 | # Ignore config.h files 95 | config.h 96 | config.h.in 97 | 98 | test/unit/test_db 99 | 100 | # test tmpdir 101 | pkcs11_fuzztest_db_take_lock_* 102 | 103 | *~ 104 | 105 | #autogen VERSION file 106 | VERSION 107 | -------------------------------------------------------------------------------- /.lgtm.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-2-Clause 2 | extraction: 3 | cpp: 4 | prepare: 5 | packages: 6 | - autoconf-archive 7 | - libcurl4-openssl-dev 8 | - libjson-c-dev 9 | - libssl-dev 10 | - uuid-dev 11 | - acl 12 | configure: 13 | command: 14 | - ./bootstrap 15 | - ./configure --disable-ptool-checks 16 | after_prepare: 17 | - cd "$LGTM_WORKSPACE" 18 | - mkdir installdir 19 | - git clone https://github.com/tpm2-software/tpm2-tss.git 20 | - cd tpm2-tss 21 | - ./bootstrap 22 | - ./configure --prefix="$LGTM_WORKSPACE/installdir/usr" --disable-doxygen-doc 23 | - make install 24 | - export PKG_CONFIG_PATH="$LGTM_WORKSPACE/installdir/usr/lib/pkgconfig:$PKG_CONFIG_PATH" 25 | - export LD_LIBRARY_PATH="$LGTM_WORKSPACE/installdir/usr/lib:$LD_LIBRARY_PATH" 26 | - cd "$LGTM_WORKSPACE" 27 | - git clone https://github.com/tpm2-software/tpm2-tools.git 28 | - cd "tpm2-tools" 29 | - ./bootstrap 30 | - ./configure --prefix="$LGTM_WORKSPACE/installdir/usr" 31 | - make install 32 | - export PATH="$LGTM_WORKSPACE/installdir/usr/bin:$PATH" 33 | - cd "$LGTM_WORKSPACE" 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without 2 | modification, are permitted provided that the following conditions are met: 3 | 4 | 1. Redistributions of source code must retain the above copyright notice, 5 | this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, 8 | this list of conditions and the following disclaimer in the documentation 9 | and/or other materials provided with the distribution. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 12 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 13 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 14 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 15 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 16 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 17 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 18 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 19 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 20 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 21 | THE POSSIBILITY OF SUCH DAMAGE. 22 | 23 | Note that: 24 | - lib/twist.c 25 | - lib/twist.h 26 | - test/unit/test_twist 27 | 28 | all eminent from https://bitbucket.org/billcroberts/twist/src/master/ 29 | Those files, the copyright is retained by William Roberts however 30 | the source is relicensed from Apache 2.0, to BSD2 by the author. 31 | 32 | Those files respect the license as documented in the respective file: 33 | - src/pkcs11.h 34 | - .gitignore 35 | -------------------------------------------------------------------------------- /Makefile-fuzz.am: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-2-Clause 2 | 3 | TEST_EXTENSIONS += .fuzz .fuzz32 4 | 5 | WRAP_LD_FLAGS := \ 6 | -Wl,--wrap=Esys_Initialize \ 7 | -Wl,--wrap=backend_fapi_init \ 8 | -Wl,--wrap=Tss2_TctiLdr_Initialize \ 9 | -Wl,--wrap=Tss2_TctiLdr_Finalize \ 10 | -Wl,--wrap=Esys_GetCapability \ 11 | -Wl,--wrap=Esys_TestParms \ 12 | -Wl,--wrap=Esys_Finalize \ 13 | -Wl,--wrap=Esys_TR_FromTPMPublic \ 14 | -Wl,--wrap=Esys_TR_Serialize \ 15 | -Wl,--wrap=Esys_TR_Deserialize \ 16 | -Wl,--wrap=Esys_TR_SetAuth \ 17 | -Wl,--wrap=Esys_StartAuthSession \ 18 | -Wl,--wrap=Esys_TRSess_SetAttributes \ 19 | -Wl,--wrap=Esys_TRSess_GetAttributes \ 20 | -Wl,--wrap=Esys_CreateLoaded \ 21 | -Wl,--wrap=Esys_Create \ 22 | -Wl,--wrap=Esys_FlushContext \ 23 | -Wl,--wrap=Esys_Load \ 24 | -Wl,--wrap=Esys_TRSess_GetAttributes \ 25 | -Wl,--wrap=Esys_Unseal \ 26 | -Wl,--wrap=Esys_ObjectChangeAuth 27 | 28 | if FUZZING 29 | 30 | FUZZ_RUNNER := $(top_srcdir)/test/fuzz/scripts/fuzz-runner.sh 31 | 32 | AM_FUZZ_LOG_FLAGS=$(FUZZING_FLAGS) 33 | FUZZ_LOG_COMPILER=$(FUZZ_RUNNER) 34 | 35 | test_fuzz_yaml_parser_fuzz_CFLAGS = $(AM_CFLAGS) $(FUZZING_CFLAGS) 36 | test_fuzz_yaml_parser_fuzz_LDADD = $(libtpm2_test_pkcs11) 37 | test_fuzz_yaml_parser_fuzz_SOURCES = test/fuzz/yaml-parser.fuzz.c 38 | 39 | test_fuzz_utils_ctx_unwrap_objauth_fuzz_CFLAGS = $(AM_CFLAGS) $(CMOCKA_CFLAGS) $(FUZZING_CFLAGS) 40 | test_fuzz_utils_ctx_unwrap_objauth_fuzz_LDADD = $(libtpm2_test_pkcs11) $(CMOCKA_LIBS) 41 | test_fuzz_utils_ctx_unwrap_objauth_fuzz_SOURCES = test/fuzz/utils-ctx-unwrap-objauth.c 42 | 43 | test_fuzz_init_token_sopin_fuzz_CFLAGS = $(AM_CFLAGS) $(FUZZING_CFLAGS) $(CMOCKA_CFLAGS) -I$(srcdir)/test/fake-tpm 44 | test_fuzz_init_token_sopin_fuzz_LDFLAGS = $(WRAP_LD_FLAGS) 45 | test_fuzz_init_token_sopin_fuzz_LDADD = $(libtpm2_test_pkcs11) $(AM_LDFLAGS) $(CMOCKA_LIBS) 46 | test_fuzz_init_token_sopin_fuzz_SOURCES = test/fuzz/init-token-sopin.fuzz.c 47 | 48 | test_fuzz_init_pin_fuzz_CFLAGS = $(AM_CFLAGS) $(FUZZING_CFLAGS) $(CMOCKA_CFLAGS) -I$(srcdir)/test/fake-tpm 49 | test_fuzz_init_pin_fuzz_LDFLAGS = $(WRAP_LD_FLAGS) 50 | test_fuzz_init_pin_fuzz_LDADD = $(libtpm2_test_pkcs11) $(AM_LDFLAGS) $(CMOCKA_LIBS) 51 | test_fuzz_init_pin_fuzz_SOURCES = test/fuzz/init-pin.fuzz.c 52 | 53 | test_fuzz_set_pin_fuzz_CFLAGS = $(AM_CFLAGS) $(FUZZING_CFLAGS) $(CMOCKA_CFLAGS) -I$(srcdir)/test/fake-tpm 54 | test_fuzz_set_pin_fuzz_LDFLAGS = $(WRAP_LD_FLAGS) 55 | test_fuzz_set_pin_fuzz_LDADD = $(libtpm2_test_pkcs11) $(AM_LDFLAGS) $(CMOCKA_LIBS) 56 | test_fuzz_set_pin_fuzz_SOURCES = test/fuzz/set-pin.fuzz.c 57 | 58 | test_fuzz_db_take_lock_fuzz_CFLAGS = $(AM_CFLAGS) $(FUZZING_CFLAGS) $(CMOCKA_CFLAGS) -I$(srcdir)/test/fake-tpm 59 | test_fuzz_db_take_lock_fuzz_LDADD = $(libtpm2_test_pkcs11) $(AM_LDFLAGS) $(CMOCKA_LIBS) 60 | test_fuzz_db_take_lock_fuzz_SOURCES = test/fuzz/db-take-lock.fuzz.c 61 | 62 | 63 | AM_FUZZ32_LOG_FLAGS=$(FUZZING_FLAGS) -max_len=32 64 | FUZZ32_LOG_COMPILER=$(FUZZ_RUNNER) 65 | 66 | test_fuzz_init_token_label_fuzz32_CFLAGS = $(AM_CFLAGS) $(FUZZING_CFLAGS) $(CMOCKA_CFLAGS) -I$(srcdir)/test/fake-tpm 67 | test_fuzz_init_token_label_fuzz32_LDFLAGS = $(WRAP_LD_FLAGS) 68 | test_fuzz_init_token_label_fuzz32_LDADD = $(libtpm2_test_pkcs11) $(AM_LDFLAGS) $(CMOCKA_LIBS) 69 | test_fuzz_init_token_label_fuzz32_SOURCES = test/fuzz/init-token-label.fuzz32.c 70 | 71 | test_fuzz_db_token_label_fuzz32_CFLAGS = $(AM_CFLAGS) $(FUZZING_CFLAGS) $(CMOCKA_CFLAGS) -I$(srcdir)/test/fake-tpm 72 | test_fuzz_db_token_label_fuzz32_LDFLAGS = $(WRAP_LD_FLAGS) 73 | test_fuzz_db_token_label_fuzz32_LDADD = $(libtpm2_test_pkcs11) $(AM_LDFLAGS) $(CMOCKA_LIBS) 74 | test_fuzz_db_token_label_fuzz32_SOURCES = test/fuzz/db-token-label.fuzz32.c 75 | 76 | fuzz_PROGRAMS = \ 77 | test/fuzz/yaml-parser.fuzz \ 78 | test/fuzz/init-token-sopin.fuzz \ 79 | test/fuzz/init-pin.fuzz \ 80 | test/fuzz/set-pin.fuzz \ 81 | test/fuzz/db-take-lock.fuzz \ 82 | test/fuzz/db-token-label.fuzz32 \ 83 | test/fuzz/init-token-label.fuzz32 \ 84 | test/fuzz/utils-ctx-unwrap-objauth.fuzz 85 | 86 | # make check will run the fuzz targets 87 | check_PROGRAMS += $(fuzz_PROGRAMS) 88 | 89 | fuzzdir = $(srcdir) 90 | fuzz-targets: $(fuzz_PROGRAMS) 91 | 92 | endif # FUZZING 93 | -------------------------------------------------------------------------------- /Makefile-unit.am: -------------------------------------------------------------------------------- 1 | ### Unit Tests ### 2 | if UNIT 3 | 4 | ## End of test libraries, start tests ## 5 | 6 | check_PROGRAMS += \ 7 | test/unit/test_twist\ 8 | test/unit/test_log \ 9 | test/unit/test_parser \ 10 | test/unit/test_attr \ 11 | test/unit/test_db \ 12 | test/unit/test_utils 13 | 14 | test_unit_test_twist_CFLAGS = $(AM_CFLAGS) $(CMOCKA_CFLAGS) 15 | test_unit_test_twist_LDADD = $(CMOCKA_LIBS) $(libtpm2_test_internal) $(libtpm2_test_pkcs11) 16 | test_unit_test_log_CFLAGS = $(AM_CFLAGS) $(CMOCKA_CFLAGS) 17 | test_unit_test_log_LDADD = $(CMOCKA_LIBS) $(libtpm2_test_internal) $(libtpm2_test_pkcs11) 18 | test_unit_test_parser_CFLAGS = $(AM_CFLAGS) $(YAML_CFLAGS) $(CMOCKA_CFLAGS) 19 | test_unit_test_parser_LDADD = $(CMOCKA_LIBS) $(YAML_LIBS) $(libtpm2_test_internal) $(libtpm2_test_pkcs11) 20 | test_unit_test_attr_CFLAGS = $(AM_CFLAGS) $(CMOCKA_CFLAGS) 21 | test_unit_test_attr_LDADD = $(CMOCKA_LIBS) $(libtpm2_test_internal) $(libtpm2_test_pkcs11) 22 | 23 | test_unit_test_db_CFLAGS = $(AM_CFLAGS) $(CMOCKA_CFLAGS) $(SQLITE3_CFLAGS) 24 | test_unit_test_db_LDADD = $(CMOCKA_LIBS) $(SQLITE3_LIBS) $(libtpm2_test_internal) $(libtpm2_test_pkcs11) 25 | test_unit_test_db_LDFLAGS = -Wl,--wrap=sqlite3_column_bytes \ 26 | -Wl,--wrap=sqlite3_column_blob \ 27 | -Wl,--wrap=sqlite3_data_count \ 28 | -Wl,--wrap=sqlite3_column_name \ 29 | -Wl,--wrap=sqlite3_column_bytes \ 30 | -Wl,--wrap=sqlite3_column_text \ 31 | -Wl,--wrap=sqlite3_column_int \ 32 | -Wl,--wrap=sqlite3_prepare_v2 \ 33 | -Wl,--wrap=sqlite3_finalize \ 34 | -Wl,--wrap=sqlite3_bind_blob \ 35 | -Wl,--wrap=sqlite3_bind_int \ 36 | -Wl,--wrap=sqlite3_bind_text \ 37 | -Wl,--wrap=sqlite3_errmsg \ 38 | -Wl,--wrap=sqlite3_step \ 39 | -Wl,--wrap=sqlite3_exec \ 40 | -Wl,--wrap=sqlite3_last_insert_rowid \ 41 | -Wl,--wrap=strdup \ 42 | -Wl,--wrap=calloc 43 | test_unit_test_utils_CFLAGS = $(AM_CFLAGS) $(CMOCKA_CFLAGS) 44 | test_unit_test_utils_LDADD = $(CMOCKA_LIBS) $(libtpm2_test_internal) $(libtpm2_test_pkcs11) 45 | 46 | endif 47 | # END UNIT 48 | 49 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-2-Clause 2 | 3 | INCLUDE_DIRS = -I$(srcdir)/src -I$(top_srcdir)/src/lib 4 | ACLOCAL_AMFLAGS = -I m4 --install 5 | AM_CFLAGS = $(INCLUDE_DIRS) $(EXTRA_CFLAGS) $(CODE_COVERAGE_CFLAGS) \ 6 | $(TSS2_ESYS_CFLAGS) $(TSS2_MU_CFLAGS) $(TSS2_TCTILDR_CFLAGS) \ 7 | $(TSS2_RC_CFLAGS) $(SQLITE3_CFLAGS) $(PTHREAD_CFLAGS) \ 8 | $(CRYPTO_CFLAGS) $(YAML_CFLAGS) $(TSS2_FAPI_CFLAGS) 9 | 10 | AM_LDFLAGS = $(EXTRA_LDFLAGS) $(CODE_COVERAGE_LIBS) $(TSS2_ESYS_LIBS) \ 11 | $(TSS2_MU_LIBS) $(TSS2_TCTILDR_LIBS) $(TSS2_RC_LIBS) \ 12 | $(SQLITE3_LIBS) $(PTHREAD_LIBS) $(CRYPTO_LIBS) $(YAML_LIBS) $(TSS2_FAPI_LIBS) 13 | 14 | check-programs: $(check_PROGRAMS) 15 | 16 | JAVAROOT=$(top_builddir)/test/integration 17 | 18 | # ax_code_coverage 19 | if AUTOCONF_CODE_COVERAGE_2019_01_06 20 | include $(top_srcdir)/aminclude_static.am 21 | clean-local: code-coverage-clean 22 | distclean-local: code-coverage-dist-clean 23 | else 24 | @CODE_COVERAGE_RULES@ 25 | endif 26 | 27 | # Add source code files from bootstrap 28 | include src_vars.mk 29 | 30 | EXTRA_DIST = \ 31 | LICENSE \ 32 | docs \ 33 | test/fake-tpm \ 34 | test/integration/scripts \ 35 | misc/p11-kit \ 36 | tools \ 37 | VERSION 38 | 39 | # Generate the AUTHORS file from git log 40 | AUTHORS : 41 | $(AM_V_GEN)git log --format='%aN <%aE>' | grep -v 'users.noreply.github.com' | sort | \ 42 | uniq -c | sort -nr | sed 's/^\s*//' | cut -d" " -f2- > $@ 43 | EXTRA_DIST += AUTHORS 44 | CLEANFILES = AUTHORS 45 | 46 | # pkg-config setup. pc-file declarations happen in the corresponding modules 47 | pkgconfig_DATA = 48 | DISTCLEANFILES = $(pkgconfig_DATA) 49 | 50 | ### PKCS#11 Library Definition ### 51 | libtpm2_pkcs11 = src/libtpm2_pkcs11.la 52 | pkgconfig_DATA += lib/tpm2-pkcs11.pc 53 | EXTRA_DIST += lib/tpm2-pkcs11.map 54 | 55 | if HAVE_LD_VERSION_SCRIPT 56 | src_libtpm2_pkcs11_la_LDFLAGS = -Wl,--version-script=$(srcdir)/lib/tpm2-pkcs11.map 57 | endif # HAVE_LD_VERSION_SCRIPT 58 | src_libtpm2_pkcs11_la_LIBADD = $(AM_LDFLAGS) 59 | src_libtpm2_pkcs11_la_SOURCES = $(LIB_PKCS11_SRC) $(LIB_PKCS11_INTERNAL_LIB_SRC) 60 | 61 | if HAVE_PREFIX 62 | # Use standard install location when using --prefix 63 | lib_LTLIBRARIES = $(libtpm2_pkcs11) 64 | else 65 | if HAVE_P11KIT 66 | # Use P11 kit library module install location 67 | p11libdir=$(P11_MODULE_PATH) 68 | p11lib_LTLIBRARIES = $(libtpm2_pkcs11) 69 | 70 | # Use P11 kit module config file install location 71 | p11configdir=$(P11_CONFIGS_PATH) 72 | p11config_DATA = $(top_srcdir)/misc/p11-kit/tpm2_pkcs11.module 73 | else 74 | # Use standard install location when P11Kit is not found 75 | lib_LTLIBRARIES = $(libtpm2_pkcs11) 76 | endif 77 | endif 78 | 79 | AM_DISTCHECK_CONFIGURE_FLAGS = --with-p11kitconfigdir='$$(datarootdir)/p11kitconfigdir' --with-p11kitmoduledir='$$(libdir)' 80 | 81 | # 82 | # Due to limitations in how cmocka works, we build a separate library here so we 83 | # can have a PKCS11 shared object with undefined calls into the rest of the lib 84 | # code. This allows us to deploy a single library, but be able to intercept calls 85 | # during linking with ld wrap to mock out various functions. 86 | # 87 | # UNIT, INTEGRATION and/or FUZZ can use this library. 88 | # 89 | 90 | # src/lib stuff as a separate archive 91 | libtpm2_test_pkcs11 = src/libtpm2_test_pkcs11.la 92 | src_libtpm2_test_pkcs11_la_LIBADD = $(AM_LDFLAGS) $(libtpm2_test_internal) 93 | src_libtpm2_test_pkcs11_la_SOURCES = $(LIB_PKCS11_SRC) 94 | 95 | # Internal Testing Unit 96 | libtpm2_test_internal = src/libtpm2_test_internal.la 97 | src_libtpm2_test_internal_la_LIBADD = $(AM_LDFLAGS) 98 | src_libtpm2_test_internal_la_SOURCES = $(LIB_PKCS11_INTERNAL_LIB_SRC) 99 | 100 | noinst_LTLIBRARIES = $(libtpm2_test_pkcs11) $(libtpm2_test_internal) 101 | 102 | if ENABLE_ASAN 103 | ASAN_ENABLED="true" 104 | else 105 | ASAN_ENABLED="" 106 | endif 107 | 108 | if HAVE_FAPI 109 | FAPI_ENABLED="true" 110 | else 111 | FAPI_ENABLED="" 112 | endif 113 | 114 | # test harness configuration 115 | AM_TESTS_ENVIRONMENT = \ 116 | ASAN_ENABLED=$(ASAN_ENABLED) \ 117 | FAPI_ENABLED=$(FAPI_ENABLED) \ 118 | T=$(abs_top_srcdir) \ 119 | PYTHON_INTERPRETER=@PYTHON_INTERPRETER@ \ 120 | TEST_FUNC_LIB=$(srcdir)/test/integration/scripts/int-test-funcs.sh \ 121 | TEST_FIXTURES=$(abs_top_srcdir)/test/integration/fixtures \ 122 | PATH=$(abs_top_srcdir)/tools:./src:$(PATH) \ 123 | PYTHONPATH=$(abs_top_srcdir)/tools:$(PYTHONPATH) \ 124 | TPM2_PKCS11_MODULE=$(abs_builddir)/src/.libs/libtpm2_pkcs11.so \ 125 | TEST_JAVA_ROOT=$(JAVAROOT) \ 126 | PACKAGE_URL=$(PACKAGE_URL) \ 127 | CC=$(CC) \ 128 | dbus-run-session 129 | 130 | TESTS_LDADD = $(noinst_LTLIBRARIES) $(lib_LTLIBRARIES) $(p11lib_LTLIBRARIES) $(AM_LDFLAGS) $(CMOCKA_LIBS) $(CRYPTO_LIBS) 131 | 132 | TESTS_CFLAGS = $(CMOCKA_CFLAGS) 133 | 134 | # Intentionally empty so INTEGRATION and UNIT tests can append to it. 135 | check_PROGRAMS = 136 | check_SCRIPTS = 137 | 138 | # include integration tests 139 | include Makefile-integration.am 140 | 141 | # include unit tests 142 | include Makefile-unit.am 143 | 144 | # Include fuzz tests 145 | include Makefile-fuzz.am 146 | 147 | TESTS= \ 148 | $(check_PROGRAMS) \ 149 | $(check_SCRIPTS) 150 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | docs/README.md -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | set -e 4 | 5 | # Generate a VERSION file that is included in the dist tarball to avoid needed git 6 | # when calling autoreconf in a release tarball. 7 | git describe --tags --always --dirty > VERSION 8 | 9 | # generate list of source files for use in Makefile.am 10 | # if you add new source files, you must run ./bootstrap again 11 | src_listvar () { 12 | basedir=$1 13 | suffix=$2 14 | var=$3 15 | 16 | find "${basedir}" -maxdepth 1 -name "${suffix}" | LC_ALL=C sort | tr '\n' ' ' | (printf "${var} = " && cat) 17 | echo "" 18 | } 19 | 20 | VARS_FILE=src_vars.mk 21 | AUTORECONF=${AUTORECONF:-autoreconf} 22 | 23 | echo "Generating file lists: ${VARS_FILE}" 24 | ( 25 | src_listvar "src" "*.c" "LIB_PKCS11_C" 26 | src_listvar "src" "*.h" "LIB_PKCS11_H" 27 | printf "LIB_PKCS11_SRC = \$(LIB_PKCS11_C) \$(LIB_PKCS11_H)\n" 28 | 29 | src_listvar "src/lib" "*.c" "LIB_PKCS11_INTERNAL_LIB_C" 30 | src_listvar "src/lib" "*.h" "LIB_PKCS11_INTERNAL_LIB_H" 31 | printf "LIB_PKCS11_INTERNAL_LIB_SRC = \$(LIB_PKCS11_INTERNAL_LIB_C) \$(LIB_PKCS11_INTERNAL_LIB_H)\n" 32 | ) > ${VARS_FILE} 33 | 34 | mkdir -p m4 35 | ${AUTORECONF} --install --sym $@ 36 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-2-Clause 2 | ignore: 3 | - test 4 | -------------------------------------------------------------------------------- /docs/ARCHITECTURE.md: -------------------------------------------------------------------------------- 1 | # tpm2-pkcs11 architecture design 2 | 3 | This document aims to describe the fundamental design of the TPM2.0 PKCS11 internals. 4 | 5 | ## Store 6 | 7 | In order to fulfill the PKCS11 interface, some additional metadata needs to be stored to disk. 8 | The data is stored in the "store", which is controllable via: 9 | - ENV Variable `TPM2_PKCS11_STORE` 10 | - Search Operation of: 11 | - `/etc/tpm2-pkcs11` 12 | - `$HOME/tpm2_pkcs11` 13 | - `$CWD` 14 | 15 | The store contains all the metadata required, and currently is stored in sqlite3 database. 16 | 17 | ## Primary Key Root 18 | 19 | Internally, all objects are stored under a **persistent** primary key in the owner hierarchy. 20 | The choice of a persistent object was done to prevent requirements of knowing the owner 21 | hierarchy auth to use the PKCS11 token. Additionally, most TPMs will have an *SRK* 22 | provisionined here as well. This authorization value is usually owned by 23 | an IT organization in enterprise environments. The auth value for this primary key 24 | is stored in the store on disk and is only protected with filesystem access controls. However, 25 | a typical Primary Key in the Owner Hierarchy has an empty password. Thus, 26 | use of the primary key should be considered a given and in most cases the auth value is 27 | empty or a known value. The primary key handle is stored as a serialized ESYS_TR in the 28 | store and is used for encrypted sessions with the TPM. 29 | 30 | ## Login Flow 31 | For each token in the store, a token maintains 2 objects under the primary key. One for 32 | each of the PKCS11 users, the SO and USER users. The authorization value for these objects 33 | is the SO or USER PIN respectively, mixed with a salt via sha256. This auth value is used 34 | to unseal an AES256 wrapping key. The wrapping key is used to encrypt all object auth 35 | values in the token, in mode GCM. 36 | 37 | ## Token Objects 38 | The actual keys and certificates that the token exposes for cryptographic operations. 39 | These keys all have an auth value that is wrapped with the token wide wrapping key. 40 | 41 | ## Expanding the Auth Model 42 | Currently, the wrapping model should make it easy to bring in existing keys into the model 43 | if needed. Most keys just use a simple password. However, in the fuure, we are looking 44 | to add policy support for internally created keys, see: 45 | - https://github.com/tpm2-software/tpm2-pkcs11/blob/master/docs/tpm2-pkcs11_object_auth_model.md 46 | 47 | 48 | -------------------------------------------------------------------------------- /docs/CHANGELOG.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tpm2-software/tpm2-pkcs11/1e5b798e2f1b0b674a97bf1149d28874779a2680/docs/CHANGELOG.md -------------------------------------------------------------------------------- /docs/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | We as members, contributors, and leaders pledge to make participation in our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, visible or invisible disability, ethnicity, sex characteristics, gender 9 | identity and expression, level of experience, education, socio-economic status, 10 | nationality, personal appearance, race, caste, color, religion, or sexual 11 | identity and orientation. 12 | 13 | We pledge to act and interact in ways that contribute to an open, welcoming, 14 | diverse, inclusive, and healthy community. 15 | 16 | ## Our Standards 17 | 18 | Examples of behavior that contributes to a positive environment for our 19 | community include: 20 | 21 | * Demonstrating empathy and kindness toward other people 22 | * Being respectful of differing opinions, viewpoints, and experiences 23 | * Giving and gracefully accepting constructive feedback 24 | * Accepting responsibility and apologizing to those affected by our mistakes, 25 | and learning from the experience 26 | * Focusing on what is best not just for us as individuals, but for the overall 27 | community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or advances of 32 | any kind 33 | * Trolling, insulting or derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or email address, 36 | without their explicit permission 37 | * Other conduct which could reasonably be considered inappropriate in a 38 | professional setting 39 | 40 | ## Enforcement Responsibilities 41 | 42 | Community leaders are responsible for clarifying and enforcing our standards of 43 | acceptable behavior and will take appropriate and fair corrective action in 44 | response to any behavior that they deem inappropriate, threatening, offensive, 45 | or harmful. 46 | 47 | Community leaders have the right and responsibility to remove, edit, or reject 48 | comments, commits, code, wiki edits, issues, and other contributions that are 49 | not aligned to this Code of Conduct, and will communicate reasons for moderation 50 | decisions when appropriate. 51 | 52 | ## Scope 53 | 54 | This Code of Conduct applies within all community spaces, and also applies when 55 | an individual is officially representing the community in public spaces. 56 | Examples of representing our community include using an official e-mail address, 57 | posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 63 | reported to the community leaders responsible for enforcement at 64 | [MAINTAINERS](MAINTAINERS). 65 | All complaints will be reviewed and investigated promptly and fairly. 66 | 67 | All community leaders are obligated to respect the privacy and security of the 68 | reporter of any incident. 69 | 70 | ## Enforcement Guidelines 71 | 72 | Community leaders will follow these Community Impact Guidelines in determining 73 | the consequences for any action they deem in violation of this Code of Conduct: 74 | 75 | ### 1. Correction 76 | 77 | **Community Impact**: Use of inappropriate language or other behavior deemed 78 | unprofessional or unwelcome in the community. 79 | 80 | **Consequence**: A private, written warning from community leaders, providing 81 | clarity around the nature of the violation and an explanation of why the 82 | behavior was inappropriate. A public apology may be requested. 83 | 84 | ### 2. Warning 85 | 86 | **Community Impact**: A violation through a single incident or series of 87 | actions. 88 | 89 | **Consequence**: A warning with consequences for continued behavior. No 90 | interaction with the people involved, including unsolicited interaction with 91 | those enforcing the Code of Conduct, for a specified period of time. This 92 | includes avoiding interactions in community spaces as well as external channels 93 | like social media. Violating these terms may lead to a temporary or permanent 94 | ban. 95 | 96 | ### 3. Temporary Ban 97 | 98 | **Community Impact**: A serious violation of community standards, including 99 | sustained inappropriate behavior. 100 | 101 | **Consequence**: A temporary ban from any sort of interaction or public 102 | communication with the community for a specified period of time. No public or 103 | private interaction with the people involved, including unsolicited interaction 104 | with those enforcing the Code of Conduct, is allowed during this period. 105 | Violating these terms may lead to a permanent ban. 106 | 107 | ### 4. Permanent Ban 108 | 109 | **Community Impact**: Demonstrating a pattern of violation of community 110 | standards, including sustained inappropriate behavior, harassment of an 111 | individual, or aggression toward or disparagement of classes of individuals. 112 | 113 | **Consequence**: A permanent ban from any sort of public interaction within the 114 | community. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 2.1, available at 120 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 121 | 122 | Community Impact Guidelines were inspired by 123 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 124 | 125 | For answers to common questions about this code of conduct, see the FAQ at 126 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 127 | [https://www.contributor-covenant.org/translations][translations]. 128 | 129 | [homepage]: https://www.contributor-covenant.org 130 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 131 | [Mozilla CoC]: https://github.com/mozilla/diversity 132 | [FAQ]: https://www.contributor-covenant.org/faq 133 | [translations]: https://www.contributor-covenant.org/translations 134 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Guidelines for submitting bugs 2 | 3 | All non security bugs can be filed on the Issues tracker: 4 | 5 | 6 | 7 | Security sensitive bugs should be handled per the instructions in the 8 | [docs/SECURITY.md](docs/SECURITY.md) file. 9 | 10 | ## Guidelines for submitting changes 11 | 12 | All changes should be introduced via GitHub pull requests. This allows anyone to 13 | comment and provide feedback in lieu of having a mailing list. For pull requests 14 | opened by non-maintainers, any maintainer may review and merge that pull request. 15 | For maintainers, they either must have their pull request reviewed by another 16 | maintainer if possible, or leave the PR open for at least 24 hours, we consider 17 | this the window for comments. 18 | 19 | * All tests must pass on Github Actions CI for the merge to occur. 20 | * All changes must not introduce superfluous whitespace changes or whitespace errors. 21 | * All changes should adhere to the coding standard documented under misc. 22 | 23 | ## Testing 24 | The Github Actions setup uses a docker container, thus this docker container can be used 25 | to run the CI testing before submitting. The rationale for using a container versus 26 | Docker directly is that: 27 | 1. Debugging build failures on Github Actions can be frustrating 28 | 2. Github Actions doesn't have support for many distributions and versions. With a container 29 | we can trivially add additional distro testing. 30 | 31 | ### How To Run Docker Locally 32 | 33 | You need to have the docker tools installed and this is not meant to be a full docker 34 | tutorial. Docker installation and usage information can be found here: 35 | - https://www.docker.com/ 36 | 37 | You can either test with CC set to gcc or clang. It is not recommended to specify versions 38 | as the container may change compiler versions and reconfigure the default at any time. If 39 | CC is empty, it defaults to gcc. It is recommended to test with both as they perform different 40 | tests, such as `scan-build` and `asan` based unit testing. 41 | 42 | **Note**: We assume that all commands are run from the tpm2-pkcs11 repo checkout directory. 43 | 44 | To test with a compiler do: 45 | ```sh 46 | # either gcc or clang 47 | export CC=clang 48 | docker run --env-file .ci/docker.env -v `pwd`:/workspace/tpm2-pkcs11 tpm2software/tpm2-tss /bin/bash -c /workspace/tpm2-pkcs11/.ci/coverity.run 49 | ``` 50 | 51 | If one wishes to test multiple compilers, it's advantageous to enter the docker 52 | container and set CC before invoking the `coverity.run` script. It won't resync, 53 | build and install the tpm2-tss, tpm2-abrmd and tpm2-tools dependencies on multiple 54 | invocations, thus saving time, for example: 55 | ```sh 56 | docker run -it --env-file .ci/docker.env -v `pwd`:/workspace/tpm2-pkcs11 tpm2software/tpm2-tss 57 | export CC=gcc 58 | /workspace/tpm2-pkcs11/.ci/coverity.run 59 | export CC=clang 60 | /workspace/tpm2-pkcs11/.ci/coverity.run 61 | ``` 62 | 63 | ## Guideline for merging changes 64 | 65 | Pull Requests MUST be assigned to an upcoming release tag. If a release milestone does 66 | not exist, the maintainer SHALL create it per the [RELEASE.md](RELEASE.md) instructions. 67 | When accepting and merging a change, the maintainer MUST edit the description field for 68 | the release milestone to add the CHANGELOG entry. 69 | 70 | Changes must be merged with the "rebase" option on github to avoid merge commits. 71 | This provides for a clear linear history. 72 | -------------------------------------------------------------------------------- /docs/DB_UPGRADE.md: -------------------------------------------------------------------------------- 1 | # DB Upgrade 2 | 3 | The tools and libraries for tpm2-pkcs11 are designed in a way where they can automatically detect 4 | and upgrade DBs (databases). This document describes the internals of this functionality and what 5 | to do when things go wrong. 6 | 7 | ## Design Summary 8 | 9 | The DB contains the table "schema", which contains a column "schema_version" that contains the 10 | current schema version of that DB. The C library itself is statically set at build time with the 11 | maximum DB version that it knows how to read. The C library and Python tools are both equipped to 12 | upgrade the DB version from schema_version 1 to the current max version they know of. 13 | 14 | When the DB is accessed, a cooperative file lock is taken to prevent races on DB schema_version 15 | checks and upgrading the DB, thus only one process accessing the `$TPM2_PKCS11_STORE` will perform 16 | the upgrade if needed. This lock is held during the schema_version check and upgrade period only, 17 | after this the normal sqlite3 read/write lock semantics are in effect. 18 | 19 | During the upgrade period, a backup copy of the DB is created in `$TPM2_PKCS11_STORE` with the ".bak" 20 | suffix, and this DB is used for the upgrade process leaving the original DB intact. If the upgrade 21 | runs correctly on the ".bak" suffix DB. The old version of the DB is renamed with the ".old" suffix, 22 | and the ".bak" file is renamed to the original DB name. As a final step, the ".old" DB is removed. 23 | Leaving you with a single, updated DB. 24 | 25 | If a DB version mismatch is detected between the library's DB version and the DB schema_version, 26 | one of two things can happen: 27 | 28 | 1. The tool or library is built for an older schema_version than the current `$TPM2_PKCS11_STORE` 29 | schema_version, the tool or library will cause an error. 30 | 31 | 2. The tool or library is built for a newer schema_version than the current `$TPM2_PKCS11_STORE` 32 | schema_version, the tool or library will cause a DB upgrade to occur. 33 | 34 | To rectify the first case, simply upgrade your tools to a version >= to the DB schema_version 35 | of the `$TPM2_PKCS11_STORE`. 36 | 37 | To rectify the second case, nothing should be required of the user, unless an unforeseen error 38 | occurs. 39 | 40 | ## Error Recovery on DB Upgrade 41 | 42 | The biggest thing to remember if you encounter an error, is that either the original DB will 43 | exist in the in the `$TPM2_PKCS11_STORE` directory, unmodified, or as a file with an extension 44 | of ".old" if something occurs during renaming. That is your original, unmodified DB. The 45 | original DB, slightly modified will exist, allowing you to manually correct it, or roll 46 | back to the original DB via a simple mv command of the ".old" suffixed file to the ".sqlite3" 47 | suffixed file. 48 | 49 | ```bash 50 | mv $TPM2_PKCS11_STORE/tpm2_pkcs11.sqlite3.old $TPM2_PKCS11_STORE/tpm2_pkcs11.sqlite3 51 | ``` 52 | 53 | If you you roll back the DB, it would be best to also roll back the tpm2-pkcs11 version to the 54 | last version successfully used. 55 | -------------------------------------------------------------------------------- /docs/FAPI.md: -------------------------------------------------------------------------------- 1 | # Integration with the Feature API (FAPI) 2 | 3 | ## Introduction 4 | 5 | The feature API is a high level API for interacting with the TPM 2.0 device. It exposes a subset of the TPM operations as well as provides on disk key management, 6 | automatic encrypted sessions and format conversions, like PEM, where possible. The tpm2-pkcs11 project predates the Feature API, and the original 7 | code was implemented using the Enhanced System API (ESAPI) and for on disk storage of TPM protected keys, a sqlite3 database. 8 | 9 | ## Configuring 10 | 11 | ## Build Time 12 | 13 | At the time the package is built, it will detect tss2-fapi library and automatically configure it's inclusion into the tpm2-pkcs11 library. One can *explicitly* configure this 14 | with `--with-fapi=yes|no`. 15 | 16 | ## Run Time 17 | 18 | If the tss2-fapi library is configured, it will dynamically attempt to locate and list tokens provisioned with tss2-fapi. Because FAPI might be in a bad state, this could cause 19 | superfluous errors and warnings. The library is built to ignore these errors, like: 20 | - 21 | 22 | You can take a few actions if you run into this issue: 23 | 1. Ignore them, and optionally disable FAPI error logging: 24 | - `export TSS2_LOG=fapi+NONE` 25 | 26 | 2. Reconfigure the package with `--with-fapi=no`: 27 | - `./configure --with-fapi=no` 28 | 29 | 3. Provision FAPI using `tss2_provision`. See the tpm2-tools project for more information: 30 | - 31 | 32 | 33 | Additionally at run time, the token creation function, C\_InitToken, may be invoked to create a new token. By default, the token always using the original 34 | mechanism of the SQLite3 database. This is to preserve backwards compatibility and behavior. To use the FAPI backend, one *must* set the environment 35 | variable `TPM2_PKCS11_BACKEND` to `fapi`. If empty, or set to `esysdb` the SQLite3 backend is used. Any other value is an error. 36 | 37 | -------------------------------------------------------------------------------- /docs/FUZZING.md: -------------------------------------------------------------------------------- 1 | # Fuzzing 2 | 3 | Tests under [test/fuzz](./test/fuzz) use libfuzzer to perform fuzzing tests on crafted targets. 4 | 5 | They are enabled by the configure time option `--enable-fuzzing` 6 | 7 | ## LibFuzzer 8 | 9 | LibFuzzer is guided evolutionary fuzzing framework. Information on libfuzzer can be found here: 10 | - https://llvm.org/docs/LibFuzzer.html 11 | 12 | ## Running the Fuzz Tests 13 | 14 | ### Step 1 - Configure Them 15 | 16 | As stated before, they are enabled by the configure time option `--enable-fuzzing`. Howevever, often times you 17 | need to also add the following options: 18 | - `--disable-hardning`: Various issues with clang not liking static initializers on complex structs, ie `struct foo x = { 0 };` 19 | - `--disable-overflow`: Clang issues with linking the runtime when __builtin's are used for overflow checking on math. 20 | 21 | With clang version 9, I was able to avoid the need for those additional configure options, however, you'll always likely 22 | want `--disable-hardening` to avoid some features that may make debugging harder. 23 | 24 | ### Step 2 - Running The Fuzz Tests 25 | 26 | Running them is as simple as make check. 27 | 28 | ```sh 29 | make check 30 | ``` 31 | 32 | You should see the normal summary from expected from a make check output. 33 | 34 | ## Internals 35 | 36 | Internally, the tests are organized under the [test/fuzz](./test/fuzz) directory and have a few subdirs: 37 | - [test/fuzz/scripts](./test/fuzz/scripts): Support scripts, like the LOG_COMPILER used as the test runner. 38 | - [test/fuzz](./test/fuzz/corpus): Contains subdirs of corpus bodies used to help guide the fuzzer and 39 | make it more efficient. 40 | 41 | ### LOG_COMPILER 42 | 43 | LOG_COMPILERS are an automake trick of saying before running the executable that is the test, run this first. It allows one 44 | to also pass options. More can be found [here](https://www.gnu.org/software/automake/manual/html_node/Parallel-Test-Harness.html). 45 | The issue with that, however, is that the granularity is per-file extension. So in this case, we define a `.fuzz` extension that 46 | all executable tests will have, and the [script](test/fuzz/scripts/fuzz-runner.sh) will wrap each execution. We define the options 47 | controlling the run duration and jobs in the script. Using something like `AM_FUZZ_LOG_FLAGS` could also be used, but we would have 48 | to then reorder the command line more to ensure that libfuzzer options appear in front of the fuzz target executable. -------------------------------------------------------------------------------- /docs/INSTALL.md: -------------------------------------------------------------------------------- 1 | # Installing 2 | 3 | Instructions on building installing from source. 4 | 5 | # Dependencies 6 | Step one is to satisfy the following dependencies: 7 | 8 | ## C Dependencies 9 | - LibYAML 10 | - libtpm2-esapi 11 | - libtpm2-mu 12 | - cmocka (optional for testing) 13 | 14 | ## Python Dependencies 15 | - cryptography 16 | - pyyaml 17 | - pyasn1 18 | - pyasn1_modules 19 | 20 | ## Executable Dependencies 21 | - python2 or python3 22 | - tpm2-tools >= 4.0 23 | - bash (optional for testing) 24 | - pkcs11-tool (optional for testing) 25 | - openssl (optional for testing) 26 | - libp11 (optional for testing) 27 | - java (optional for testing) 28 | - junit (optional for testing) 29 | - hamcrest (optional for testing) 30 | 31 | Details on building can be found in [BUILDING.md](BUILDING.md). 32 | 33 | After satisfying the dependencies one invokes the regular autotools build process: 34 | ```bash 35 | ./bootstrap 36 | ./configure 37 | make 38 | make install 39 | ``` 40 | # Installing tpm2_ptool.py 41 | 42 | To install tpm2_ptool.py, one can use various python installation methodologies as a setup.py file is provided. 43 | Below are the common ways to install, but are not exhaustive. 44 | 45 | First cd to the tools folder: 46 | ```bash 47 | cd tools 48 | ``` 49 | Then perform one of: 50 | 1. ```bash 51 | # pip allows for easy user installs via option --user and thus doesn't require root 52 | pip install . 53 | ``` 54 | 2. ```bash 55 | easy_install setup.py 56 | ``` 57 | -------------------------------------------------------------------------------- /docs/MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # Maintainers 2 | 3 | * Juergen Repp 4 | * Andreas Fuchs 5 | * Bill Roberts 6 | -------------------------------------------------------------------------------- /docs/OPENSSL.md: -------------------------------------------------------------------------------- 1 | # Using TPM2 PKCS11 with OpenSSL 2 | 3 | ## Introduction 4 | 5 | OpenSSL has the ability to load dynamic engines to control where the underlying cryptographic 6 | operations occur. Additionally, [OpenSC LibP11](https://github.com/OpenSC/libp11) has an engine 7 | that can load arbitrary PKCS11 libraries. Thus, through a few layer of indirections, you can use 8 | OpenSSL with the tpm2-pkcs11 library. This is a less complete tutorial, and assumes you have 9 | been through the [pkcs11-tool](PKCS11_TOOL.md) tutorial. 10 | 11 | ## Setup 12 | 13 | Yubico has very complete instructions for configuring, see: 14 | - https://developers.yubico.com/YubiHSM2/Usage_Guides/OpenSSL_with_pkcs11_engine.html 15 | 16 | These instructions are mostly applicable, the only thing that needs to change is that the 17 | MODULE_PATH needs to point to the tpm2-pkcs11 library. 18 | 19 | A sample OSSL config file is provided at [openssl.conf](../misc/tpm2-pkcs11.openssl.sample.conf). 20 | 21 | Note: 22 | - The Yubico instructions use rand. Rand will not hit the tpm because the OpenSC engine does 23 | not support it. 24 | - Systems with PKCS11 kit installed may need additional tweaks to get it to work. 25 | 26 | For the examples below, I followed Yubico's advice and set up an alias in my `~/.bashrc` file 27 | called tpm2ssl, like so: 28 | ```bash 29 | alias tpm2ssl='OPENSSL_CONF=$HOME/tpm2-pkcs11.openssl.conf openssl' 30 | ``` 31 | 32 | You'll also need to set up a `TPM2_PKCS11_STORE` and have an asymmetric key pair generated. This is all 33 | shown in the [pkcs11-tool](PKCS11_TOOL.md) tutorial. 34 | 35 | Setting up an alias makes life easier, so lets do that: 36 | ```bash 37 | alias tpm2pkcs11-tool='pkcs11-tool --module /path/to/libtpm2_pkcs11.so 38 | ``` 39 | Note: You need to update `--module` option to point to the tpm2-pcks11 shared object. 40 | 41 | ## Generating a Certificate 42 | 43 | First thing first, identify the private key to use to generate the certificate or CSR from. With pkcs11-tool, one can 44 | do: 45 | ```bash 46 | pkcs11-tool --module /path/to/libtpm2_pkcs11.so --slot 1 --login -O 47 | ``` 48 | You should see output like so: 49 | ```bash 50 | Private Key Object; EC 51 | label: my-ecc-keypair 52 | ID: 61366566303531343635636138663035 53 | Usage: decrypt, sign 54 | ``` 55 | 56 | Note: You need to login to see private key objects. 57 | 58 | If you don't have a key, we can create one: 59 | ```bash 60 | tpm2pkcs11-tool --label="my-ecc-keypair" --login --keypairgen --usage-sign --key-type EC:prime256v1 61 | Using slot 0 with a present token (0x1) 62 | Key pair generated: 63 | Private Key Object; EC 64 | label: my-ecc-keypair 65 | ID: 3436 66 | Usage: sign 67 | Public Key Object; EC EC_POINT 256 bits 68 | EC_POINT: 04410436e7d2c84725234ec8d4b14bc31a50d382eb578cbc7315ae95561875314eb5a22a390bbfabef6269a35a18b1d95b2abc553071c419c3e866db0c3f13c0288ac6 69 | EC_PARAMS: 06082a8648ce3d030107 70 | label: my-ecc-keypair 71 | ID: 3437 72 | Usage: verify 73 | ``` 74 | 75 | Your key could be RSA, that's fine. The imporant thing is to look at the label and pass it via the `-key` argument 76 | in openssl below. Note that this is key my-ecc-keypair in slot 1, even though the output says slot 0. In PKCS11, the slotid is what matters, which is the 0x1. A slot id of 0x0 is not valid. 77 | 78 | To generate a self signed certificate, one can simply use the `req` command with `openssl`. 79 | 80 | ``` bash 81 | tpm2ssl req -new -x509 -days 365 -subj '/CN=my key/' -sha256 -engine pkcs11 -keyform engine -key slot_1-label_my-ecc-keypair -out cert.pem 82 | engine "pkcs11" set. 83 | Enter PKCS#11 token PIN for label: 84 | ``` 85 | 86 | Note: OpenSSL can also find the key by using the `id` field. For example, update the key to: 87 | ``` 88 | -key slot_1-id_38316235653539316533633232383139 89 | ``` 90 | 91 | ## Generating a CSR 92 | 93 | Most users will likely require certificates signed by a CA. To do this, we can generate a CSR that gets uploaded to a CA. The CA 94 | then returns the certificate. The steps to upload the CSR and retrieve it from the CA are CA dependent and will not be covered 95 | here. 96 | 97 | ```bash 98 | tpm2ssl req -new -subj '/CN=my key/' -sha256 -engine pkcs11 -keyform engine -key slot_1-label_my-ecc-keypair -out csr.pem 99 | ``` 100 | 101 | The next steps after generating the CSR would be to go to a CA, get a certificate generated and signed using it. 102 | 103 | Note: 104 | - OpenSSL config file can be used for specifying default values when using the req command. 105 | [See the man page](https://www.openssl.org/docs/man1.1.1/man1/openssl-req.html). 106 | 107 | ## Inserting a Certificate 108 | 109 | At this point, you have a certificate, either self signed or signed via a CA. The certificate may be in many forms, 110 | if you followed the steps above, it's in the PEM format. You need to convert any version you have to PEM, information 111 | on how to do this can be found at: 112 | - https://knowledge.digicert.com/solution/SO26449.html 113 | 114 | Once you obtain a PEM certificate, you can use the ptool command. 115 | 116 | ```bash 117 | tpm2_ptool addcert --label=label --key-id=38316235653539316533633232383139 --path=$TPM2_PKCS11_STORE ~/pem 118 | action: add 119 | cert: 120 | CKA_ID: '38316235653539316533633232383139' 121 | ``` 122 | 123 | ## Listing a Certificate 124 | 125 | After this, view your cert object, you can again just list the objects with pkcs11-tool. 126 | 127 | ```bash 128 | tpm2pkcs11-tool --slot 1 -O 129 | ``` 130 | 131 | You should see, amongst other output, output like: 132 | 133 | ```bash 134 | Certificate Object; type = X.509 cert 135 | label: 1 136 | subject: DN: CN=my key 137 | ID: 38316235653539316533633232383139 138 | ``` 139 | -------------------------------------------------------------------------------- /docs/PKCS11_TOOL.md: -------------------------------------------------------------------------------- 1 | # pkcs11 tool Configuration 2 | 3 | Below, will be examples and discussion on how to use tpm2-pkcs11 with pkcs11-tool. 4 | 5 | pkcs11-tool is part of OpenSC and can be installed on ubuntu by issuing the command: 6 | ```sh 7 | sudo apt-get install opensc 8 | ``` 9 | 10 | # Step 1 - Initializing a Store 11 | 12 | Start by reading the document on initialization [here](INITIALIZING.md). Only brief commands 13 | will be provided here, so a basic understanding of the initialization process is paramount. 14 | 15 | We start by creating a tpm2-pkcs11 *store* and set up an empty token. 16 | 17 | ```bash 18 | tpm2_ptool.py init --path=~/tmp 19 | 20 | tpm2_ptool.py addtoken --pid=1 --sopin=mysopin --userpin=myuserpin --label=label --path ~/tmp 21 | ``` 22 | 23 | # Step 2 - Exporting the Store 24 | 25 | Since we didn't use the default store location by setting `--path` in the `tpm2-ptool` tool, we must export the 26 | store so the library can find it. We do this via: 27 | ```bash 28 | export TPM2_PKCS11_STORE=$HOME/tmp 29 | ``` 30 | 31 | **Note**: The tpm2-pkcs11.so library *WILL NOT EXPAND `~`* and thus you have to use something the shell will expand, 32 | like `$HOME`. 33 | 34 | # Examples of pkcs11-tool 35 | 36 | This will not be exhaustive, as we do not wish to duplicate opensc's documentation of their tool. But we will show case 37 | a few commands for users wishing to use this tool with tpm2-pkcs11 project. 38 | 39 | **For each example below, --module is the path to the pkcs11.so library and will be machine dependent. Note that default builds 40 | will provide the library under src/.libs** 41 | 42 | It makes life simpler to set up an alias, so let's do that, making sure to update `--module`: 43 | 44 | ```bash 45 | alias tpm2pkcs11-tool='pkcs11-tool --module /path/to/libtpm2_pkcs11.so 46 | ``` 47 | 48 | ## Changing USER PIN 49 | 50 | How to change the user PIN from *myuserpin* to *mynewpin* 51 | 52 | ```sh 53 | tpm2pkcs11-tool --label="label" --login --pin myuserpin --change-pin --new-pin mynewpin 54 | Using slot 0 with a present token (0x1) 55 | PIN successfully changed 56 | ``` 57 | You can see [Checking USER PIN](#checking-user-pin) for example of checking the PIN. 58 | 59 | ## Checking USER PIN 60 | 61 | How to check that the PIN is valid. The PIN value shown is based off of section [Changing USER PIN](#changing-user-pin) 62 | 63 | ```sh 64 | tpm2pkcs11-tool --label="label" --test --pin mynewpin 65 | ``` 66 | 67 | ## Initializing USER PIN 68 | 69 | How to reset or initialize the user PIN given the SO PIN. 70 | ```sh 71 | tpm2pkcs11-tool --label="label" --init-pin --so-pin mysopin --pin mynewpin 72 | ``` 73 | 74 | ## Generating Random Data 75 | 76 | The below example will generate 4 bytes of random data and assumes the PIN has been changed as in section 77 | [Checking USER PIN](#checking-user-pin) for example of checking the PIN. 78 | 79 | ```bash 80 | tpm2pkcs11-tool --label="label" --pin mynewpin --generate-random 4 | xxd 81 | Using slot 0 with a present token (0x1) 82 | 00000000: 2e50 bc47 .P.G 83 | ``` 84 | 85 | ## Listing Objects 86 | 87 | To list objects, we simply use the `--list-objects` option: 88 | ```bash 89 | tpm2pkcs11-tool --list-objects 90 | Private Key Object; EC 91 | label: p11-templ-key-label-ecc 92 | ID: 7031312d74656d706c2d6b65792d69642d65636300 93 | Usage: sign 94 | Public Key Object; EC EC_POINT 256 bits 95 | EC_POINT: 04410452526c163439c3c5e5a943466a606439fbc7284eafd12221c4473ecb2fba3c586816d54f9ff108489877c5cfa857ba05cfba33dfe3e9b739107f672f787838d6 96 | EC_PARAMS: 06082a8648ce3d030107 97 | label: p11-templ-key-label-ecc 98 | ID: 7031312d74656d706c2d6b65792d69642d65636300 99 | Usage: verify 100 | ``` 101 | 102 | **Note**: Your output will likely differ, but the tool should output a list of objects and some attributes. 103 | 104 | ## Creating Objects 105 | 106 | Outside of using [tpm2_ptool.py](PKCS11_TOOL.md) to add objects, p11tool supports creating objects 107 | through the PKCS#11 interface. 108 | 109 | ### Generating RSA Key pair 110 | 111 | This will generate an RSA key pair using pkcs11-tool: 112 | ```bash 113 | tpm2pkcs11-tool --label="label" --login --pin=myuserpin --keypairgen 114 | Using slot 0 with a present token (0x1) 115 | Key pair generated: 116 | Private Key Object; RSA 117 | label: label 118 | ID: 3332 119 | Usage: none 120 | Public Key Object; RSA 2048 bits 121 | label: label 122 | ID: 3333 123 | Usage: none 124 | ``` 125 | 126 | ### Generating ECC Key pair 127 | 128 | This will generate an EC key pair using pkcs11-tool: 129 | ```bash 130 | tpm2pkcs11-tool --label="my-ecc-keypair" --login --pin=myuserpin --keypairgen --usage-sign --key-type EC:prime256v1 131 | Using slot 0 with a present token (0x1) 132 | Key pair generated: 133 | Private Key Object; EC 134 | label: my-ecc-keypair 135 | ID: 3436 136 | Usage: sign 137 | Public Key Object; EC EC_POINT 256 bits 138 | EC_POINT: 04410436e7d2c84725234ec8d4b14bc31a50d382eb578cbc7315ae95561875314eb5a22a390bbfabef6269a35a18b1d95b2abc553071c419c3e866db0c3f13c0288ac6 139 | EC_PARAMS: 06082a8648ce3d030107 140 | label: my-ecc-keypair 141 | ID: 3437 142 | Usage: verify 143 | ``` 144 | 145 | ## Destroying Objects 146 | 147 | Let's destroy the key we created in the *Generating ECC Key pair* segment, IDs 3436 and 3437 for both the private and public portions 148 | respectively. 149 | 150 | ### Private Key 151 | ```bash 152 | tpm2pkcs11-tool --login --pin=myuserpin --delete-object --type=privkey --id 3436 153 | Using slot 0 with a present token (0x1) 154 | ``` 155 | ### Public Key 156 | ```bash 157 | tpm2pkcs11-tool --login --pin=myuserpin --delete-object --type=pubkey --id 3437 158 | Using slot 0 with a present token (0x1) 159 | ``` 160 | 161 | **Note**: The tool doesn't have any output about successful delete, only when it fails. However, you can run the command 162 | in *Listing Objects* to verify that it is indeed deleted. 163 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # tpm2-pkcs11 2 | 3 | [![Build Status](https://github.com/tpm2-software/tpm2-pkcs11/workflows/CI/badge.svg)](https://github.com/tpm2-software/tpm2-pkcs11/actions) 4 | [![Coverage Status](https://codecov.io/gh/tpm2-software/tpm2-pkcs11/branch/master/graph/badge.svg)](https://codecov.io/gh/tpm2-software/tpm2-pkcs11) 5 | [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/tpm2-software/tpm2-pkcs11.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/tpm2-software/tpm2-pkcs11/context:cpp) 6 | [![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/tpm2-software/tpm2-pkcs11.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/tpm2-software/tpm2-pkcs11/context:python) 7 | [![Coverity Scan](src="https://img.shields.io/coverity/scan/16909.svg")](https://scan.coverity.com/projects/tpm2-pkcs11) 8 | 9 | PKCS #11 is a Public-Key Cryptography Standard that defines a standard method to 10 | access cryptographic services from tokens/ devices such as hardware security 11 | modules (HSM), smart cards, etc. In this project we intend to use a TPM2 device 12 | as the cryptographic token. 13 | 14 | # Getting Started 15 | 16 | * [Building](/docs/BUILDING.md) - How to get it to build 17 | * [Initializing](/docs/INITIALIZING.md) - How to configure it 18 | * [Installing](/docs/INSTALL.md) - How to install it 19 | 20 | # Example Usages 21 | * [SSH](/docs/SSH.md) - How to configure and use it with SSH. 22 | * [P11](/docs/P11.md) - How to configure and use it with various P11 components. 23 | * [PKCS11-TOOL](/docs/PKCS11_TOOL.md) - How to configure and use it with OpenSC's pkcs11-tool. 24 | * [EAP-TLS](/docs/EAP-TLS.md) - How to configure and use it for Wi-Fi authentication using EAP-TLS. 25 | * [INTEROPERABILITY](/docs/INTEROPERABILITY.md) - Configuration details for interoperability with 26 | [tss2-engine](https://github.com/tpm2-software/tpm2-tss-engine) and 27 | [tpm2-tools](https://github.com/tpm2-software/tpm2-tools) projects. Note, the *tpm2-tools* interoperability 28 | could cover other projects that use raw *marshalled* TPM 2.0 structures. 29 | 30 | # Advanced Knowledge 31 | * [Architecture](/docs/ARCHITECTURE.md) - Internal Overview 32 | * [DB Upgrades](/docs/DB_UPGRADE.md) - What happens on a DB Version Upgrade 33 | * [Release Process](/docs/RELEASE.md) - How releases are conducted 34 | -------------------------------------------------------------------------------- /docs/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Currently supported versions: 6 | 7 | | Version | Supported | 8 | | -------- | ------------------ | 9 | | < 1.5.0 | :x: | 10 | | >= 1.5.0 | :white_check_mark: | 11 | 12 | ## Reporting a Vulnerability 13 | 14 | ### Reporting 15 | 16 | Security vulnerabilities can be disclosed in one of two ways: 17 | - GitHub: *preferred* By following [these](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability) instructions. 18 | - Email: A descirption *should be emailed* to **all** members of the [MAINTAINERS](MAINTAINERS) file to coordinate the 19 | disclosure of the vulnerability. 20 | 21 | ### Tracking 22 | 23 | When a maintainer is notified of a security vulnerability, they *must* create a GitHub security advisory 24 | per the instructions at: 25 | 26 | - 27 | 28 | Maintainers *should* use the optional feature through GitHub to request a CVE be issued, alternatively RedHat has provided CVE's 29 | in the past and *may* be used, but preference is on GitHub as the issuing CNA. 30 | 31 | ### Publishing 32 | 33 | Once ready, maintainers should publish the security vulnerability as outlined in: 34 | 35 | - 36 | 37 | As well as ensuring the publishing of the CVE, maintainers *shal*l have new release versions ready to publish at the same time as 38 | the CVE. Maintainers *should* should strive to adhere to a sub 60 say turn around from report to release. 39 | -------------------------------------------------------------------------------- /docs/SSH.md: -------------------------------------------------------------------------------- 1 | # SSH Configuration 2 | 3 | Below, will be examples and discussion on how to configure SSH with tpm2-pkcs11 to ssh to 4 | the local host. The example described here could be extended for remote ssh login as well. 5 | 6 | We assume a machine configured in such a state where a user can ssh locally and login with 7 | a password prompt, ala: 8 | ```sh 9 | ssh user@127.0.0.1 10 | user@127.0.0.1's password: 11 | Last login: Thu Sep 6 12:23:07 2018 from 127.0.0.1 12 | ``` 13 | works. 14 | 15 | **Thus we assume a working ssh server, client and ssh-keygen services and utilities are present.** 16 | 17 | # Step 1 - Initializing a Store 18 | 19 | Start by reading the document on initialization [here](INITIALIZING.md). Only brief commands 20 | will be provided here, so a basic understanding of the initialization process is paramount. 21 | 22 | We start by creating a tpm2-pkcs11 *store* and set up an RSA2048 key that SSH can used. 23 | **Note**: Most SSH configurations allow RSA2048 keys to be used, but this can be turned off 24 | in the config, but this is quite rare. 25 | 26 | ```bash 27 | tpm2_ptool.py init --path=~/tmp 28 | 29 | tpm2_ptool.py addtoken --pid=1 --label=label --sopin=mysopin --userpin=myuserpin --path=~/tmp 30 | 31 | tpm2_ptool.py addkey --algorithm=rsa2048 --label=label --userpin=myuserpin --path=~/tmp 32 | ``` 33 | 34 | # Step 2 - Exporting the Store 35 | 36 | Since we didn't use the default store location by setting `--path` in the `tpm2-ptool` tool, we must export the 37 | store so the library can find it. We do this via: 38 | ```sh 39 | export TPM2_PKCS11_STORE=$HOME/tmp 40 | ``` 41 | 42 | **Note**: The tpm2-pkcs11.so library *WILL NOT EXPAND `~`* and thus you have to use something the shell will expand, 43 | like `$HOME`. 44 | 45 | # Step 3 - Generating the SSH key public portion 46 | 47 | The next step will use `ssh-keygen` command to generate the public portion of an ssh key. The command is slightly complicated 48 | as we use tee to redirect the output to both a file called `my.pub` and to *stdout* for viewing. 49 | 50 | Note: You may need to update the path to the tpm2-pkcs11 shared object below. 51 | 52 | ```bash 53 | ssh-keygen -D ./src/.libs/libtpm2_pkcs11.so | tee my.pub 54 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0CTmUAAB8jfNNHrw99m7K3U/+qbV1pAb7es3L+COqDh4eDqqekCm8gKHV4PFM9nW7z6CEfqzpUxYi5VvRFdYaU460bhye7NJbE0t9wjOirWtQbI6XMCKFiv/v8ThAtROT+KKYso7BK2A6spkCQwcHoaQU72C1vGouqtP5l/XRIYydp3P1wUdgQDZ8FoGhdH5dL3KnRpKR2d301GcbxMxKg5yhc/mTNkv1ZoLIcwMY7juAjzin/BhcYIDSz3sJ9C2VsX8FZXmbEo3olYU4ZfBZ+45KJ81MtWgrkXSzetwUfiH6eeTqNfqGT2IpSwDLFHTX2TsJyFDcM7Q+QR44lEU/ 55 | ``` 56 | 57 | # Step 4 - Configuring SSH to Accept the Key 58 | 59 | Now that the public portion of the key is in ssh format and located in file `my.pub` we can add this to the `authorized_keys2` file for the user: 60 | ```bash 61 | cat my.pub >> ~/.ssh/authorized_keys2 62 | ``` 63 | 64 | SSH consults this file and trusts private keys corresponding with the public entries. 65 | 66 | # Step 5 - Ensuring the Library is in a Good Path 67 | 68 | Using the ssh client, we login. Note that ssh won't accept pkcs11 libraries outside of "trusted" locations. So we copy the PKCS\#11 library to 69 | a trusted location. Thus you can either do `sudo make install` to move the binary to a trusted location or just do it manually. 70 | 71 | Manual Method: 72 | ```sh 73 | sudo cp src/.libs/libtpm2_pkcs11.so /usr/local/lib/libtpm2_pkcs11.so 74 | ``` 75 | 76 | On Ubuntu 16.04 with no configuration options specified to alter installation locations, they end up in the same location for both the *manual method* 77 | and `sudo make install` method. 78 | 79 | # Step 6 - Logging In via SSH 80 | 81 | To log in, one used the `ssh` client application and specifies the path to the PKCS11 library via the `-I` option. It will prompt for the user PIN, which 82 | in the example is set to `myuserpin`. 83 | 84 | ```bash 85 | ssh -I /usr/local/lib/libtpm2_pkcs11.so 127.0.0.1 86 | Enter PIN for 'label': myuserpin 87 | Last login: Fri Sep 21 13:28:31 2018 from 127.0.0.1 88 | ``` 89 | 90 | You are now logged in with a key resident in the TPM being exported via the tpm2-pkcs11 library. 91 | -------------------------------------------------------------------------------- /docs/SSH_HOSTKEYS.md: -------------------------------------------------------------------------------- 1 | # SSH host keys configuration 2 | 3 | This example will go through using a TPM 2.0 for the OpenSSH sshd host keys. 4 | As the SSH daemon supports using the SSH agent protocol we will use tpm2-pkcs11 with an ssh-agent. 5 | 6 | # Create a store and key 7 | The PIN is currently needed as ssh-agent doesn't seem to support an empty string PIN (just no PIN at all) 8 | ``` 9 | # mkdir /tmp/teststore-pkcs11 10 | # tpm2_ptool init --path=/tmp/teststore-pkcs11 11 | # tpm2_ptool addtoken --pid=1 --label=hostkey --sopin="mysopin" --userpin="myuserpin" --path=/tmp/teststore-pkcs11 12 | # tpm2_ptool addkey --algorithm=rsa2048 --label=hostkey --userpin="myuserpin" --path=/tmp/teststore-pkcs11 13 | ``` 14 | 15 | # Run a ssh agent 16 | The ssh agent should have a specific path for its socket, lets use /tmp/hostagent.sock for this example. 17 | ``` 18 | # export TPM2_PKCS11_STORE=/tmp/teststore-pkcs11 19 | # ssh-agent -a /tmp/hostagent.sock 20 | ``` 21 | 22 | # Add the token to the agent 23 | ``` 24 | # SSH_AUTH_SOCK=/tmp/hostagent.sock ssh-add -s /usr/lib/x86_64-linux-gnu/libtpm2_pkcs11.so 25 | ``` 26 | 27 | # Get the public key in SSH format 28 | ``` 29 | # SSH_AUTH_SOCK=/tmp/hostagent.sock ssh-add -L 30 | ssh-rsa .... 31 | ``` 32 | Where `....` is the public key in ssh key format. 33 | Store the whole output from ssh-add -L in `/etc/ssh/ssh_hostkey_rsa.pub` as sshd requires the public key outside the agent. 34 | 35 | # Configure sshd 36 | Add the following to /etc/ssh/sshd_config 37 | ``` 38 | HostKey /etc/ssh/ssh_hostkey_rsa.pub 39 | HostKeyAgent /tmp/hostagent.sock 40 | ``` 41 | (Re)start sshd and run: 42 | ``` 43 | # ssh-keyscan localhost 44 | ``` 45 | You should now be able to see the same key as you saw with `ssh-add -L`. 46 | 47 | -------------------------------------------------------------------------------- /docs/illustrations/cisco_e1500_wireless_config.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tpm2-software/tpm2-pkcs11/1e5b798e2f1b0b674a97bf1149d28874779a2680/docs/illustrations/cisco_e1500_wireless_config.jpg -------------------------------------------------------------------------------- /docs/illustrations/object_diagram_nv_objects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tpm2-software/tpm2-pkcs11/1e5b798e2f1b0b674a97bf1149d28874779a2680/docs/illustrations/object_diagram_nv_objects.png -------------------------------------------------------------------------------- /docs/illustrations/object_diagram_transient_objects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tpm2-software/tpm2-pkcs11/1e5b798e2f1b0b674a97bf1149d28874779a2680/docs/illustrations/object_diagram_transient_objects.png -------------------------------------------------------------------------------- /docs/illustrations/pkcs11_api_classification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tpm2-software/tpm2-pkcs11/1e5b798e2f1b0b674a97bf1149d28874779a2680/docs/illustrations/pkcs11_api_classification.png -------------------------------------------------------------------------------- /docs/illustrations/policy_model_nv_objects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tpm2-software/tpm2-pkcs11/1e5b798e2f1b0b674a97bf1149d28874779a2680/docs/illustrations/policy_model_nv_objects.png -------------------------------------------------------------------------------- /docs/illustrations/policy_model_transient_objects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tpm2-software/tpm2-pkcs11/1e5b798e2f1b0b674a97bf1149d28874779a2680/docs/illustrations/policy_model_transient_objects.png -------------------------------------------------------------------------------- /docs/illustrations/reader-slot-token-obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tpm2-software/tpm2-pkcs11/1e5b798e2f1b0b674a97bf1149d28874779a2680/docs/illustrations/reader-slot-token-obj.png -------------------------------------------------------------------------------- /lib/tpm2-pkcs11.def: -------------------------------------------------------------------------------- 1 | LIBRARY tpm2-pkcs11 2 | EXPORTS 3 | C_Initialize 4 | C_Finalize 5 | C_GetInfo 6 | C_GetFunctionList 7 | C_GetSlotList 8 | C_GetSlotInfo 9 | C_GetTokenInfo 10 | C_GetMechanismList 11 | C_GetMechanismInfo 12 | C_InitToken 13 | C_InitPIN 14 | C_SetPIN 15 | C_OpenSession 16 | C_CloseSession 17 | C_CloseAllSessions 18 | C_GetSessionInfo 19 | C_GetOperationState 20 | C_SetOperationState 21 | C_Login 22 | C_Logout 23 | C_CreateObject 24 | C_CopyObject 25 | C_DestroyObject 26 | C_GetObjectSize 27 | C_GetAttributeValue 28 | C_SetAttributeValue 29 | C_FindObjectsInit 30 | C_FindObjects 31 | C_FindObjectsFinal 32 | C_EncryptInit 33 | C_Encrypt 34 | C_EncryptUpdate 35 | C_EncryptFinal 36 | C_DecryptInit 37 | C_Decrypt 38 | C_DecryptUpdate 39 | C_DecryptFinal 40 | C_DigestInit 41 | C_Digest 42 | C_DigestUpdate 43 | C_DigestKey 44 | C_DigestFinal 45 | C_SignInit 46 | C_Sign 47 | C_SignUpdate 48 | C_SignFinal 49 | C_SignRecoverInit 50 | C_SignRecover 51 | C_VerifyInit 52 | C_Verify 53 | C_VerifyUpdate 54 | C_VerifyFinal 55 | C_VerifyRecoverInit 56 | C_VerifyRecover 57 | C_DigestEncryptUpdate 58 | C_DecryptDigestUpdate 59 | C_SignEncryptUpdate 60 | C_DecryptVerifyUpdate 61 | C_GenerateKey 62 | C_GenerateKeyPair 63 | C_WrapKey 64 | C_UnwrapKey 65 | C_DeriveKey 66 | C_SeedRandom 67 | C_GenerateRandom 68 | C_GetFunctionStatus 69 | C_CancelFunction 70 | C_WaitForSlotEvent 71 | -------------------------------------------------------------------------------- /lib/tpm2-pkcs11.map: -------------------------------------------------------------------------------- 1 | { 2 | global: 3 | C_Initialize; 4 | C_Finalize; 5 | C_GetInfo; 6 | C_GetFunctionList; 7 | C_GetSlotList; 8 | C_GetSlotInfo; 9 | C_GetTokenInfo; 10 | C_GetMechanismList; 11 | C_GetMechanismInfo; 12 | C_InitToken; 13 | C_InitPIN; 14 | C_SetPIN; 15 | C_OpenSession; 16 | C_CloseSession; 17 | C_CloseAllSessions; 18 | C_GetSessionInfo; 19 | C_GetOperationState; 20 | C_SetOperationState; 21 | C_Login; 22 | C_Logout; 23 | C_CreateObject; 24 | C_CopyObject; 25 | C_DestroyObject; 26 | C_GetObjectSize; 27 | C_GetAttributeValue; 28 | C_SetAttributeValue; 29 | C_FindObjectsInit; 30 | C_FindObjects; 31 | C_FindObjectsFinal; 32 | C_EncryptInit; 33 | C_Encrypt; 34 | C_EncryptUpdate; 35 | C_EncryptFinal; 36 | C_DecryptInit; 37 | C_Decrypt; 38 | C_DecryptUpdate; 39 | C_DecryptFinal; 40 | C_DigestInit; 41 | C_Digest; 42 | C_DigestUpdate; 43 | C_DigestKey; 44 | C_DigestFinal; 45 | C_SignInit; 46 | C_Sign; 47 | C_SignUpdate; 48 | C_SignFinal; 49 | C_SignRecoverInit; 50 | C_SignRecover; 51 | C_VerifyInit; 52 | C_Verify; 53 | C_VerifyUpdate; 54 | C_VerifyFinal; 55 | C_VerifyRecoverInit; 56 | C_VerifyRecover; 57 | C_DigestEncryptUpdate; 58 | C_DecryptDigestUpdate; 59 | C_SignEncryptUpdate; 60 | C_DecryptVerifyUpdate; 61 | C_GenerateKey; 62 | C_GenerateKeyPair; 63 | C_WrapKey; 64 | C_UnwrapKey; 65 | C_DeriveKey; 66 | C_SeedRandom; 67 | C_GenerateRandom; 68 | C_GetFunctionStatus; 69 | C_CancelFunction; 70 | C_WaitForSlotEvent; 71 | local: 72 | *; 73 | }; 74 | -------------------------------------------------------------------------------- /lib/tpm2-pkcs11.pc.in: -------------------------------------------------------------------------------- 1 | p11_module_path=@P11_MODULE_PATH@ 2 | 3 | Name: tpm2-pkcs11 4 | Description: TPM2 PKCS#11 library 5 | URL: https://github.com/tpm2-software/tpm2-pkcs11 6 | Version: @VERSION@ 7 | Requires.private: tss2-esys tss2-mu sqlite3 libcrypto 8 | Cflags: @PTHREAD_CFLAGS@ 9 | Libs: -L${p11_module_path} -ltpm2_pkcs11 10 | Libs.private: @PTHREAD_LIBS@ 11 | -------------------------------------------------------------------------------- /m4/ld-version-script.m4: -------------------------------------------------------------------------------- 1 | # ld-version-script.m4 serial 4 2 | dnl Copyright (C) 2008-2019 Free Software Foundation, Inc. 3 | dnl This file is free software; the Free Software Foundation 4 | dnl gives unlimited permission to copy and/or distribute it, 5 | dnl with or without modifications, as long as this notice is preserved. 6 | 7 | dnl From Simon Josefsson 8 | 9 | # FIXME: The test below returns a false positive for mingw 10 | # cross-compiles, 'local:' statements does not reduce number of 11 | # exported symbols in a DLL. Use --disable-ld-version-script to work 12 | # around the problem. 13 | 14 | # gl_LD_VERSION_SCRIPT 15 | # -------------------- 16 | # Check if LD supports linker scripts, and define automake conditional 17 | # HAVE_LD_VERSION_SCRIPT if so. 18 | AC_DEFUN([gl_LD_VERSION_SCRIPT], 19 | [ 20 | AC_ARG_ENABLE([ld-version-script], 21 | [AS_HELP_STRING([--enable-ld-version-script], 22 | [enable linker version script (default is enabled when possible)])], 23 | [have_ld_version_script=$enableval], 24 | [AC_CACHE_CHECK([if LD -Wl,--version-script works], 25 | [gl_cv_sys_ld_version_script], 26 | [gl_cv_sys_ld_version_script=no 27 | save_LDFLAGS=$LDFLAGS 28 | LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map" 29 | echo foo >conftest.map 30 | AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], 31 | [], 32 | [cat > conftest.map < 7 | 8 | #include "attrs.h" 9 | #include "debug.h" 10 | #include "pkcs11.h" 11 | #include "token.h" 12 | #include "twist.h" 13 | #include "utils.h" 14 | 15 | /* 16 | * This HAS to be smaller than 1 byte, as this is embedded 17 | * in the top byte of the session handle. 18 | */ 19 | #define MAX_TOKEN_CNT 255 20 | 21 | typedef struct pobject_v3 pobject_v3; 22 | struct pobject_v3 { 23 | int id; 24 | char *hierarchy; 25 | twist handle; 26 | char *objauth; 27 | }; 28 | 29 | typedef struct pobject_v4 pobject_v4; 30 | struct pobject_v4 { 31 | int id; 32 | char *hierarchy; 33 | char *config; 34 | char *objauth; 35 | }; 36 | 37 | CK_RV db_init(void); 38 | CK_RV db_destroy(void); 39 | 40 | CK_RV db_get_tokens(token *t, size_t *len); 41 | 42 | CK_RV db_update_for_pinchange( 43 | token *tok, 44 | bool is_so, 45 | 46 | /* new seal object auth metadata */ 47 | twist newauthsalthex, 48 | 49 | /* private and public blobs */ 50 | twist newprivblob, 51 | twist newpubblob); 52 | 53 | CK_RV db_init_pobject(unsigned pid, pobject *pobj, tpm_ctx *tpm); 54 | 55 | CK_RV db_add_new_object(token *tok, tobject *tobj); 56 | 57 | /** 58 | * Delete a tobject from the DB. 59 | * @param tobj 60 | * The tobject to remove. 61 | * @return 62 | */ 63 | CK_RV db_delete_object(tobject *tobj); 64 | 65 | CK_RV db_get_first_pid(unsigned *id); 66 | 67 | CK_RV db_add_primary(pobject *pobj, unsigned *pid); 68 | 69 | CK_RV db_add_token(token *tok); 70 | 71 | CK_RV db_update_token_config(token *tok); 72 | 73 | CK_RV db_update_tobject_attrs(unsigned id, attr_list *attrs); 74 | 75 | /* Debug testing */ 76 | #ifdef TESTING 77 | #include 78 | 79 | #include "twist.h" 80 | 81 | int get_blob_null(sqlite3_stmt *stmt, int i, twist *blob); 82 | int get_blob(sqlite3_stmt *stmt, int i, twist *blob); 83 | tobject *db_tobject_new(sqlite3_stmt *stmt); 84 | tobject *__real_db_tobject_new(sqlite3_stmt *stmt); 85 | int init_pobject_v3_from_stmt(sqlite3_stmt *stmt, pobject_v3 *old_pobj); 86 | int init_tobjects(token *tok); 87 | int __real_init_tobjects(token *tok); 88 | CK_RV convert_pobject_v3_to_v4(pobject_v3 *old_pobj, pobject_v4 *new_pobj); 89 | CK_RV db_add_pobject_v4(sqlite3 *updb, pobject_v4 *new_pobj); 90 | int init_pobject_from_stmt(sqlite3_stmt *stmt, tpm_ctx *tpm, pobject *pobj); 91 | int init_pobject(unsigned pid, pobject *pobj, tpm_ctx *tpm); 92 | int __real_init_pobject(unsigned pid, pobject *pobj, tpm_ctx *tpm); 93 | int init_sealobjects(unsigned tokid, sealobject *sealobj); 94 | int __real_init_sealobjects(unsigned tokid, sealobject *sealobj); 95 | int get_lock_path(const char *path, char *lockpath); 96 | FILE *take_lock(const char *path, char *lockpath); 97 | #endif 98 | 99 | #endif /* SRC_PKCS11_LIB_DB_H_ */ 100 | -------------------------------------------------------------------------------- /src/lib/debug.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef SRC_LIB_DEBUG_H_ 4 | #define SRC_LIB_DEBUG_H_ 5 | #include "config.h" 6 | 7 | #if defined(FUZZING) || defined(UNIT_TESTING) || !defined(NDEBUG) 8 | #define WEAK __attribute__((weak)) 9 | #define DEBUG_VISIBILITY 10 | #define TESTING 1 11 | #else 12 | #define WEAK 13 | #define DEBUG_VISIBILITY static 14 | #endif 15 | 16 | #endif /* SRC_LIB_DEBUG_H_ */ 17 | -------------------------------------------------------------------------------- /src/lib/derive.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef _SRC_LIB_DERIVE_H_ 4 | #define _SRC_LIB_DERIVE_H_ 5 | 6 | #include "pkcs11.h" 7 | #include "session_ctx.h" 8 | 9 | CK_RV derive(session_ctx *ctx, 10 | CK_MECHANISM *mechanism, 11 | CK_OBJECT_HANDLE tpm_key, 12 | CK_ATTRIBUTE_PTR secret_template, 13 | CK_ULONG secret_template_count, 14 | CK_OBJECT_HANDLE_PTR secret); 15 | #endif 16 | -------------------------------------------------------------------------------- /src/lib/digest.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef SRC_LIB_DIGEST_H_ 4 | #define SRC_LIB_DIGEST_H_ 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "object.h" 12 | #include "pkcs11.h" 13 | #include "session_ctx.h" 14 | 15 | typedef struct digest_op_data digest_op_data; 16 | struct digest_op_data { 17 | tobject *tobj; 18 | CK_MECHANISM mechanism; 19 | EVP_MD_CTX *mdctx; 20 | }; 21 | 22 | digest_op_data *digest_op_data_new(void); 23 | void digest_op_data_free(digest_op_data **opdata); 24 | 25 | CK_RV digest_init_op(session_ctx *ctx, digest_op_data *supplied_opdata, CK_MECHANISM_PTR mechanism); 26 | static inline CK_RV digest_init(session_ctx *ctx, CK_MECHANISM_PTR mechanism) { 27 | return digest_init_op(ctx, NULL, mechanism); 28 | } 29 | 30 | CK_RV digest_update_op(session_ctx *ctx, digest_op_data *supplied_opdata, CK_BYTE_PTR part, CK_ULONG part_len); 31 | static inline CK_RV digest_update(session_ctx *ctx, unsigned char *part, unsigned long part_len) { 32 | return digest_update_op(ctx, NULL, part, part_len); 33 | } 34 | 35 | CK_RV digest_final_op(session_ctx *ctx, digest_op_data *supplied_opdata, CK_BYTE_PTR digest, CK_ULONG_PTR digest_len); 36 | static inline CK_RV digest_final(session_ctx *ctx, unsigned char *digest, unsigned long *digest_len) { 37 | return digest_final_op(ctx, NULL, digest, digest_len); 38 | } 39 | 40 | CK_RV digest_oneshot(session_ctx *ctx, unsigned char *data, unsigned long data_len, unsigned char *digest, unsigned long *digest_len); 41 | 42 | #endif /* SRC_LIB_DIGEST_H_ */ 43 | -------------------------------------------------------------------------------- /src/lib/emitter.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef SRC_LIB_EMITTER_H_ 4 | #define SRC_LIB_EMITTER_H_ 5 | 6 | #include "attrs.h" 7 | #include "debug.h" 8 | #include "pkcs11.h" 9 | #include "token.h" 10 | 11 | char *emit_attributes_to_string(attr_list *attrs); 12 | 13 | char *emit_config_to_string(token *tok); 14 | 15 | char *emit_pobject_to_conf_string(pobject_config *pobj); 16 | 17 | #endif /* SRC_LIB_EMITTER_H_ */ 18 | -------------------------------------------------------------------------------- /src/lib/encrypt.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef SRC_LIB_ENCRYPT_H_ 4 | #define SRC_LIB_ENCRYPT_H_ 5 | 6 | #include 7 | 8 | #include "mech.h" 9 | #include "pkcs11.h" 10 | #include "tpm.h" 11 | #include "twist.h" 12 | 13 | typedef struct token token; 14 | 15 | typedef struct sw_encrypt_data sw_encrypt_data; 16 | typedef struct encrypt_op_data encrypt_op_data; 17 | 18 | typedef union crypto_op_data crypto_op_data; 19 | union crypto_op_data{ 20 | tpm_op_data *tpm_opdata; 21 | sw_encrypt_data *sw_enc_data; 22 | }; 23 | 24 | struct encrypt_op_data { 25 | bool use_sw; 26 | crypto_op_data cryptopdata; 27 | }; 28 | 29 | struct sw_encrypt_data { 30 | int padding; 31 | twist label; 32 | const EVP_MD *md; 33 | EVP_PKEY *key; 34 | }; 35 | 36 | encrypt_op_data *encrypt_op_data_new(void); 37 | void encrypt_op_data_free(encrypt_op_data **opdata); 38 | 39 | CK_RV sw_encrypt_data_init(mdetail *mdtl, 40 | CK_MECHANISM *mechanism, tobject *tobj, sw_encrypt_data **enc_data); 41 | 42 | CK_RV encrypt_init_op (session_ctx *ctx, encrypt_op_data *supplied_opdata, CK_MECHANISM *mechanism, CK_OBJECT_HANDLE key); 43 | static inline CK_RV encrypt_init(session_ctx *ctx, CK_MECHANISM *mechanism, CK_OBJECT_HANDLE key) { 44 | return encrypt_init_op(ctx, NULL, mechanism, key); 45 | } 46 | 47 | CK_RV encrypt_update_op (session_ctx *ctx, encrypt_op_data *supplied_opdata, unsigned char *part, unsigned long part_len, unsigned char *encrypted_part, unsigned long *encrypted_part_len); 48 | static inline CK_RV encrypt_update (session_ctx *ctx, unsigned char *part, unsigned long part_len, unsigned char *encrypted_part, unsigned long *encrypted_part_len) { 49 | return encrypt_update_op (ctx, NULL, part, part_len, encrypted_part, encrypted_part_len); 50 | } 51 | 52 | CK_RV encrypt_final_ex (session_ctx *ctx, encrypt_op_data *supplied_opdata, unsigned char *last_encrypted_part, unsigned long *last_encrypted_part_len, bool is_oneshot); 53 | 54 | static inline CK_RV encrypt_final (session_ctx *ctx, unsigned char *last_encrypted_part, unsigned long *last_encrypted_part_len) { 55 | return encrypt_final_ex (ctx, NULL, last_encrypted_part, last_encrypted_part_len, false); 56 | } 57 | 58 | CK_RV decrypt_init_op (session_ctx *ctx, encrypt_op_data *supplied_opdata, CK_MECHANISM *mechanism, CK_OBJECT_HANDLE key); 59 | static inline CK_RV decrypt_init (session_ctx *ctx, CK_MECHANISM *mechanism, CK_OBJECT_HANDLE key) { 60 | return decrypt_init_op (ctx, NULL, mechanism, key); 61 | } 62 | 63 | CK_RV decrypt_update_op (session_ctx *ctx, encrypt_op_data *supplied_opdata, unsigned char *part, unsigned long part_len, unsigned char *encrypted_part, unsigned long *encrypted_part_len); 64 | static inline CK_RV decrypt_update (session_ctx *ctx, unsigned char *part, unsigned long part_len, unsigned char *encrypted_part, unsigned long *encrypted_part_len) { 65 | return decrypt_update_op (ctx, NULL, part, part_len, encrypted_part, encrypted_part_len); 66 | } 67 | 68 | CK_RV decrypt_final_ex(session_ctx *ctx, encrypt_op_data *supplied_opdata, unsigned char *last_part, unsigned long *last_part_len, bool is_oneshot); 69 | 70 | static inline CK_RV decrypt_final (session_ctx *ctx, unsigned char *last_part, unsigned long *last_part_len) { 71 | return decrypt_final_ex (ctx, NULL, last_part, last_part_len, false); 72 | } 73 | 74 | CK_RV decrypt_oneshot_op (session_ctx *ctx, encrypt_op_data *supplied_opdata, unsigned char *encrypted_data, unsigned long encrypted_data_len, unsigned char *data, unsigned long *data_len); 75 | static inline CK_RV decrypt_oneshot (session_ctx *ctx, unsigned char *encrypted_data, unsigned long encrypted_data_len, unsigned char *data, unsigned long *data_len) { 76 | return decrypt_oneshot_op (ctx, NULL, encrypted_data, encrypted_data_len, data, data_len); 77 | } 78 | 79 | CK_RV encrypt_oneshot_op (session_ctx *ctx, encrypt_op_data *supplied_opdata, unsigned char *data, unsigned long data_len, unsigned char *encrypted_data, unsigned long *encrypted_data_len); 80 | static inline CK_RV encrypt_oneshot (session_ctx *ctx, unsigned char *data, unsigned long data_len, unsigned char *encrypted_data, unsigned long *encrypted_data_len) { 81 | return encrypt_oneshot_op (ctx, NULL, data, data_len, encrypted_data, encrypted_data_len); 82 | } 83 | 84 | #endif /* SRC_LIB_ENCRYPT_H_ */ 85 | -------------------------------------------------------------------------------- /src/lib/general.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef SRC_PKCS11_GENERAL_H_ 4 | #define SRC_PKCS11_GENERAL_H_ 5 | 6 | #include 7 | 8 | #include "pkcs11.h" 9 | 10 | CK_RV general_init(void *init_args); 11 | CK_RV general_get_func_list(CK_FUNCTION_LIST **function_list); 12 | CK_RV general_get_info(CK_INFO *info); 13 | bool general_is_init(void); 14 | 15 | CK_RV general_finalize(void *reserved); 16 | 17 | #endif /* SRC_GENERAL_H_ */ 18 | -------------------------------------------------------------------------------- /src/lib/key.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef SRC_PKCS11_KEY_H_ 4 | #define SRC_PKCS11_KEY_H_ 5 | 6 | #include "pkcs11.h" 7 | 8 | typedef struct token token; 9 | typedef struct session_ctx session_ctx; 10 | 11 | CK_RV key_gen ( 12 | session_ctx *ctx, 13 | 14 | CK_MECHANISM_PTR mechanism, 15 | 16 | CK_ATTRIBUTE_PTR public_key_template, 17 | CK_ULONG public_key_attribute_count, 18 | 19 | CK_ATTRIBUTE_PTR private_key_template, 20 | CK_ULONG private_key_attribute_count, 21 | 22 | CK_OBJECT_HANDLE_PTR public_key, 23 | CK_OBJECT_HANDLE_PTR private_key); 24 | 25 | #endif /* SRC_PKCS11_KEY_H_ */ 26 | -------------------------------------------------------------------------------- /src/lib/list.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef LIST_H_ 4 | #define LIST_H_ 5 | 6 | typedef struct list list; 7 | struct list { 8 | list *next; 9 | list *prev; 10 | }; 11 | 12 | #define list_entry(element, type, name) \ 13 | (type *)(((uint8_t *)(element)) - (uint8_t *)&(((type *)NULL)->name)) 14 | 15 | #define list_for_each(list, var) \ 16 | for(var = list; var != NULL; var = var->next) 17 | 18 | #endif /* LIST_H_ */ 19 | -------------------------------------------------------------------------------- /src/lib/log.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef SRC_PKCS11_LOG_H_ 4 | #define SRC_PKCS11_LOG_H_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #if defined (__GNUC__) 12 | #define COMPILER_ATTR(...) __attribute__((__VA_ARGS__)) 13 | #else 14 | #define COMPILER_ATTR(...) 15 | #endif 16 | 17 | typedef enum log_level log_level; 18 | enum log_level { 19 | log_level_error, 20 | log_level_warn, 21 | log_level_verbose, 22 | log_level_unknown, 23 | }; 24 | static const char *log_strings[] = { 25 | "ERROR", 26 | "WARNING", 27 | "INFO", 28 | "UNKNOWN", 29 | }; 30 | 31 | #define _LOGV(filename, lineno, fmt, ...) _log(log_level_verbose, filename, lineno, fmt, ##__VA_ARGS__) 32 | #define _LOGW(filename, lineno, fmt, ...) _log(log_level_warn, filename, lineno, fmt, ##__VA_ARGS__) 33 | #define _LOGE(filename, lineno, fmt, ...) _log(log_level_error, filename, lineno, fmt, ##__VA_ARGS__) 34 | 35 | #define LOGV(fmt, ...) _LOGV(__FILE__, __LINE__, fmt, ##__VA_ARGS__) 36 | #define LOGW(fmt, ...) _LOGW(__FILE__, __LINE__, fmt, ##__VA_ARGS__) 37 | #define LOGE(fmt, ...) _LOGE(__FILE__, __LINE__, fmt, ##__VA_ARGS__) 38 | 39 | static log_level _g_current_log_level = log_level_warn; 40 | 41 | static inline void log_set_level(const char *level_str) { 42 | 43 | if (!level_str) { 44 | return; 45 | } 46 | 47 | char *endptr; 48 | errno = 0; 49 | unsigned long value = strtoul(level_str, &endptr, 0); 50 | if (errno || *endptr != '\0') { 51 | fprintf(stderr, "Could not change log level, got: \"%s\"\n", level_str); 52 | return; 53 | } 54 | 55 | /* 56 | * Use a switch to check value, as enum may be signed or 57 | * unsigned and when unsigned checking less than can cause 58 | * the compiler to complain. 59 | */ 60 | switch(value) { 61 | case log_level_error: 62 | case log_level_warn: 63 | case log_level_verbose: 64 | _g_current_log_level = value; 65 | break; 66 | default: 67 | fprintf(stderr, "Could not change log level, got: \"%s\"\n", level_str); 68 | return; 69 | } 70 | } 71 | 72 | static inline void _log(log_level level, const char *file, unsigned lineno, 73 | const char *fmt,...) { 74 | 75 | /* override config with env var if set */ 76 | log_set_level(getenv("TPM2_PKCS11_LOG_LEVEL")); 77 | 78 | 79 | /* Skip printing messages outside of the log level */ 80 | if (level > _g_current_log_level) { 81 | return; 82 | } 83 | 84 | va_list argptr; 85 | va_start(argptr, fmt); 86 | 87 | /* Verbose output prints file and line on error */ 88 | if (_g_current_log_level >= log_level_verbose) { 89 | fprintf(stderr, "%s on line: \"%u\" in file: \"%s\": ", 90 | log_strings[level], lineno, file); 91 | } 92 | else { 93 | fprintf(stderr, "%s: ", log_strings[level]); 94 | } 95 | 96 | /* Print the user supplied message */ 97 | vfprintf(stderr, fmt, argptr); 98 | 99 | /* always add a new line so the user doesn't have to */ 100 | fprintf(stderr, "\n"); 101 | 102 | va_end(argptr); 103 | } 104 | 105 | #endif /* SRC_PKCS11_LOG_H_ */ 106 | -------------------------------------------------------------------------------- /src/lib/mech.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #include 3 | 4 | #include 5 | 6 | #include "attrs.h" 7 | #include "object.h" 8 | #include "pkcs11.h" 9 | #include "token.h" 10 | #include "tpm.h" 11 | 12 | #ifndef SRC_LIB_MECH_H_ 13 | #define SRC_LIB_MECH_H_ 14 | 15 | typedef struct mdetail mdetail; 16 | 17 | CK_RV mdetail_new(tpm_ctx *ctx, mdetail **mout, pss_config_state pss_sig_state); 18 | 19 | void mdetail_free(mdetail **mdtl); 20 | 21 | CK_RV mech_validate(mdetail *mdtl, CK_MECHANISM_PTR mech, attr_list *attrs); 22 | 23 | CK_RV mech_synthesize(mdetail *mdtl, 24 | CK_MECHANISM_PTR mech, attr_list *attrs, 25 | CK_BYTE_PTR inbuf, CK_ULONG inlen, 26 | CK_BYTE_PTR outbuf, CK_ULONG_PTR outlen); 27 | 28 | CK_RV mech_unsynthesize( 29 | mdetail *mdtl, 30 | CK_MECHANISM_PTR mech, attr_list *attrs, 31 | CK_BYTE_PTR inbuf, CK_ULONG inlen, 32 | CK_BYTE_PTR outbuf, CK_ULONG_PTR outlen); 33 | 34 | CK_RV mech_is_synthetic(mdetail *mdtl, 35 | CK_MECHANISM_PTR mech, 36 | bool *is_synthetic); 37 | 38 | CK_RV mech_get_supported(mdetail *mdtl, 39 | CK_MECHANISM_TYPE_PTR mechlist, CK_ULONG_PTR count); 40 | 41 | CK_RV mech_is_hashing_needed( 42 | mdetail *mdtl, 43 | CK_MECHANISM_PTR mech, 44 | bool *is_hashing_needed); 45 | 46 | CK_RV mech_is_hashing_knowledge_needed(mdetail *m, 47 | CK_MECHANISM_PTR mech, 48 | bool *is_hashing_knowledge_needed); 49 | 50 | CK_RV mech_get_digest_alg(mdetail *mdtl, 51 | CK_MECHANISM_PTR mech, 52 | CK_MECHANISM_TYPE *mech_type); 53 | 54 | CK_RV mech_get_digester(mdetail *mdtl, 55 | CK_MECHANISM_PTR mech, 56 | const EVP_MD **md); 57 | 58 | CK_RV mech_get_tpm_opdata(mdetail *mdtl, tpm_ctx *tctx, 59 | CK_MECHANISM_PTR mech, tobject *tobj, tpm_op_data **opdata); 60 | 61 | CK_RV mech_get_info(mdetail *mdtl, tpm_ctx *tctx, 62 | CK_MECHANISM_TYPE mech_type, CK_MECHANISM_INFO_PTR info); 63 | 64 | CK_RV mech_get_padding(mdetail *mdtl, 65 | CK_MECHANISM_PTR mech, int *padding); 66 | 67 | CK_RV mech_get_label(CK_MECHANISM_PTR mech, twist *label); 68 | 69 | void mdetail_set_pss_status(mdetail *m, bool pss_sigs_good); 70 | 71 | CK_RV mech_is_HMAC(mdetail *m, CK_MECHANISM_PTR mech, bool *is_hmac); 72 | 73 | CK_RV mech_is_ecc(mdetail *m, CK_MECHANISM_TYPE mech_type, bool *is_ecc); 74 | 75 | #endif /* SRC_LIB_MECH_H_ */ 76 | -------------------------------------------------------------------------------- /src/lib/mutex.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #include "config.h" 4 | #include 5 | 6 | #include 7 | 8 | #include "log.h" 9 | #include "mutex.h" 10 | #include "pkcs11.h" 11 | 12 | /* 13 | * Default handlers for mutex operations 14 | */ 15 | static CK_RV default_mutex_create(void **mutex); 16 | static CK_RV default_mutex_destroy(void *mutex); 17 | static CK_RV default_mutex_lock(void *mutex); 18 | static CK_RV default_mutex_unlock(void *mutex); 19 | 20 | /* 21 | * Function pointers for the actual registered 22 | * mutex operation. 23 | */ 24 | static CK_CREATEMUTEX _g_create = default_mutex_create; 25 | static CK_DESTROYMUTEX _g_destroy = default_mutex_destroy; 26 | static CK_LOCKMUTEX _g_lock = default_mutex_lock; 27 | static CK_UNLOCKMUTEX _g_unlock = default_mutex_unlock; 28 | 29 | void mutex_set_handlers(CK_CREATEMUTEX create, 30 | CK_DESTROYMUTEX destroy, 31 | CK_LOCKMUTEX lock, 32 | CK_UNLOCKMUTEX unlock) { 33 | 34 | /* 35 | * We assume the caller checked all of these are set to either 36 | * NULL or fn-ptrs and NOT a mix. 37 | */ 38 | 39 | _g_create = create; 40 | _g_destroy = destroy; 41 | _g_lock = lock; 42 | _g_unlock = unlock; 43 | } 44 | 45 | static CK_RV default_mutex_create(void **mutex) { 46 | 47 | int rc; 48 | 49 | pthread_mutex_t *p = calloc(1, sizeof(pthread_mutex_t)); 50 | if (!p) { 51 | LOGE("oom"); 52 | return CKR_HOST_MEMORY; 53 | } 54 | 55 | pthread_mutexattr_t *attr = NULL; 56 | /* 57 | * When NOT NOT DEBUGGING, ie when building in DEBUG mode 58 | * (autotools uses NDEBUG for this, hence the double 59 | * negative) enable error checking mutexes to prevent 60 | * double locks and have assert() cause an abort(). 61 | */ 62 | #ifndef NDEBUG 63 | pthread_mutexattr_t __attr; 64 | attr = &__attr; 65 | 66 | rc = pthread_mutexattr_init(attr); 67 | if (rc) { 68 | LOGE("Failed to initialize pthread attribute: %s\n", 69 | strerror(rc)); 70 | free(p); 71 | return CKR_GENERAL_ERROR; 72 | } 73 | 74 | rc = pthread_mutexattr_settype(attr, PTHREAD_MUTEX_ERRORCHECK); 75 | if (rc) { 76 | LOGE("Could not set attribute type: %s", strerror(rc)); 77 | free(p); 78 | return CKR_GENERAL_ERROR; 79 | } 80 | #endif 81 | 82 | rc = pthread_mutex_init(p, attr); 83 | if (rc) { 84 | LOGE("Could not initialize mutex: %s", strerror(rc)); 85 | free(p); 86 | return CKR_GENERAL_ERROR; 87 | } 88 | 89 | *mutex = p; 90 | return CKR_OK; 91 | } 92 | 93 | static CK_RV default_mutex_destroy(void *mutex) { 94 | 95 | pthread_mutex_t *p = (pthread_mutex_t *)mutex; 96 | if (!p) { 97 | return CKR_OK; 98 | } 99 | 100 | int rc = pthread_mutex_destroy(p); 101 | if (rc) { 102 | LOGE("Could not destroy mutex: %s", strerror(rc)); 103 | return CKR_MUTEX_BAD; 104 | } 105 | 106 | free(p); 107 | 108 | return CKR_OK; 109 | } 110 | 111 | static CK_RV default_mutex_lock(void *mutex) { 112 | 113 | pthread_mutex_t *p = (pthread_mutex_t *)mutex; 114 | 115 | int rc = pthread_mutex_lock(p); 116 | if (rc) { 117 | LOGE("Could not lock mutex: %s", strerror(rc)); 118 | return CKR_MUTEX_BAD; 119 | } 120 | 121 | return CKR_OK; 122 | } 123 | 124 | static CK_RV default_mutex_unlock(void *mutex) { 125 | 126 | pthread_mutex_t *p = (pthread_mutex_t *)mutex; 127 | 128 | int rc = pthread_mutex_unlock(p); 129 | if (rc) { 130 | LOGE("Could not unlock mutex: %s", strerror(rc)); 131 | return CKR_MUTEX_BAD; 132 | } 133 | 134 | return CKR_OK; 135 | } 136 | 137 | 138 | CK_RV mutex_create(void **mutex) { 139 | 140 | if (!_g_create) { 141 | return CKR_OK; 142 | } 143 | 144 | return _g_create(mutex); 145 | } 146 | 147 | CK_RV mutex_destroy(void *mutex) { 148 | 149 | if (!_g_destroy) { 150 | return CKR_OK; 151 | } 152 | 153 | return _g_destroy(mutex); 154 | } 155 | 156 | CK_RV mutex_lock(void *mutex) { 157 | 158 | if (!_g_lock) { 159 | return CKR_OK; 160 | } 161 | 162 | return _g_lock(mutex); 163 | } 164 | 165 | CK_RV mutex_unlock(void *mutex) { 166 | 167 | if (!_g_unlock) { 168 | return CKR_OK; 169 | } 170 | 171 | return _g_unlock(mutex); 172 | } 173 | -------------------------------------------------------------------------------- /src/lib/mutex.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef SRC_PKCS11_MUTEX_H_ 4 | #define SRC_PKCS11_MUTEX_H_ 5 | #include "config.h" 6 | #include 7 | 8 | #include "log.h" 9 | #include "pkcs11.h" 10 | #include "utils.h" 11 | 12 | /** 13 | * Set's the mutex handlers. The mutex handlers default to internal 14 | * pthread mutexes unless specifically set, or cleared by setting NULL. 15 | * @param create 16 | * The handler for creating a MUTEX. 17 | * @param destroy 18 | * The handler for destroying a MUTEX. 19 | * @param lock 20 | * The handler for locking a MUTEX. 21 | * @param unlock 22 | * The handler for unlocking a MUTEX. 23 | */ 24 | void mutex_set_handlers(CK_CREATEMUTEX create, 25 | CK_DESTROYMUTEX destroy, 26 | CK_LOCKMUTEX lock, 27 | CK_UNLOCKMUTEX unlock); 28 | 29 | /** 30 | * Allocates and initializes a mutex. 31 | * @param mutex 32 | * The pointer to store the mutext at. 33 | * @return 34 | * CKR_OK on success. 35 | */ 36 | CK_RV mutex_create(void **mutex); 37 | 38 | /** 39 | * Deallocates and destroys a mutex. 40 | * @param mutex 41 | * The mutex to deallocate. 42 | * @return 43 | * CKR_OK on success. 44 | */ 45 | CK_RV mutex_destroy(void *mutex); 46 | 47 | /** 48 | * locks a mutex. 49 | * @param mutex 50 | * The mutex to lock. 51 | * @return 52 | * CKR_OK on success. 53 | */ 54 | CK_RV mutex_lock(void *mutex); 55 | 56 | /** 57 | * unlocks a mutex. 58 | * @param mutex 59 | * The mutex to unlock. 60 | * @return 61 | * CKR_OK on success. 62 | */ 63 | CK_RV mutex_unlock(void *mutex); 64 | 65 | static inline void _mutex_lock_fatal(void *mutex) { 66 | 67 | CK_RV rv = mutex_lock(mutex); 68 | assert(rv == CKR_OK); 69 | UNUSED(rv); 70 | } 71 | 72 | static inline void _mutex_unlock_fatal(void *mutex) { 73 | 74 | CK_RV rv = mutex_unlock(mutex); 75 | assert(rv == CKR_OK); 76 | UNUSED(rv); 77 | } 78 | 79 | #ifndef NDEBUG 80 | /* 81 | * debugging lock macros, the LOGV is on the top line to report lineno correctly 82 | */ 83 | #define mutex_lock_fatal(mutex) do { LOGV("LOCK(%p)-attempt", mutex); \ 84 | _mutex_lock_fatal(mutex); \ 85 | LOGV("LOCK(%p)-aquired", mutex); \ 86 | } while (0) 87 | 88 | #define mutex_unlock_fatal(mutex) do { LOGV("UNLOCK(%p)-attempt", mutex); \ 89 | _mutex_unlock_fatal(mutex); \ 90 | LOGV("UNLOCK(%p)-released", mutex); \ 91 | } while (0) 92 | #else 93 | #define mutex_lock_fatal(mutex) _mutex_lock_fatal(mutex) 94 | #define mutex_unlock_fatal(mutex) _mutex_unlock_fatal(mutex) 95 | #endif 96 | #endif /* SRC_PKCS11_MUTEX_H_ */ 97 | -------------------------------------------------------------------------------- /src/lib/object.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef SRC_PKCS11_OBJECT_H_ 4 | #define SRC_PKCS11_OBJECT_H_ 5 | 6 | #include 7 | #include 8 | 9 | #include "attrs.h" 10 | #include "debug.h" 11 | #include "list.h" 12 | #include "pkcs11.h" 13 | #include "twist.h" 14 | 15 | typedef struct session_ctx session_ctx; 16 | typedef struct pobject pobject; 17 | 18 | typedef struct tobject tobject; 19 | struct tobject { 20 | 21 | unsigned active; /** number of active users */ 22 | 23 | unsigned id; /** external handle */ 24 | 25 | CK_OBJECT_HANDLE obj_handle; /** application visible handle */ 26 | 27 | /* 28 | * these all exist in the attribute array, but we'll keep some 29 | * twist copies of them handy for convenience. 30 | */ 31 | twist pub; /** public tpm data */ 32 | twist priv; /** private tpm data */ 33 | twist objauth; /** wrapped object auth value */ 34 | 35 | attr_list *attrs; /** object attributes */ 36 | 37 | list l; /** list pointer for "listifying" tobjects */ 38 | 39 | twist unsealed_auth; /** unwrapped auth value */ 40 | 41 | uint32_t tpm_esys_tr; /** loaded ESYS_TR */ 42 | twist tpm_serialized_tr; /** serialized ESYS_TR **/ 43 | 44 | bool is_authenticated; /** true if a context specific login has authenticated use of the object */ 45 | }; 46 | 47 | tobject *tobject_new(void); 48 | 49 | /** 50 | * Sets the internal private and public TPM data blob fields via deep copy. 51 | * Thus the caller is still responsible to free the priv and pub parameters. 52 | * @param tobj 53 | * The tobject to set. 54 | * @param pub 55 | * The public portion, cannot be NULL. 56 | * @param priv 57 | * The private portion, may be NULL. 58 | * @return 59 | * CKR_OK on success or CKR_HOST_MEMORY. 60 | */ 61 | CK_RV tobject_set_blob_data(tobject *tobj, twist pub, twist priv); 62 | 63 | /** 64 | * Sets the internal TPm auth fields via deep copy. 65 | * Thus the caller is still responsible to free the authbin and pub wrappedauthhex. 66 | * @param tobj 67 | * The tobject to set. 68 | * @param authbin 69 | * The auth in plaintext binary form. 70 | * @param wrappedauthhex 71 | * The wrapping key wrapped auth. 72 | * @return 73 | * CKR_OK on success or CKR_HOST_MEMORY. 74 | */ 75 | CK_RV tobject_set_auth(tobject *tobj, twist authbin, twist wrappedauthhex); 76 | 77 | void tobject_set_esys_tr(tobject *tobj, uint32_t esys_tr); 78 | void tobject_set_id(tobject *tobj, unsigned id); 79 | void tobject_free(tobject *tobj); 80 | 81 | CK_RV object_find_init(session_ctx *ctx, CK_ATTRIBUTE_PTR templ, unsigned long count); 82 | 83 | CK_RV object_find(session_ctx *ctx, CK_OBJECT_HANDLE *object, unsigned long max_object_count, unsigned long *object_count); 84 | 85 | CK_RV object_find_final(session_ctx *ctx); 86 | 87 | CK_RV object_get_attributes(session_ctx *ctx, CK_OBJECT_HANDLE object, CK_ATTRIBUTE *templ, unsigned long count); 88 | 89 | CK_RV object_set_attributes(session_ctx *ctx, CK_OBJECT_HANDLE object, CK_ATTRIBUTE *templ, unsigned long count); 90 | 91 | CK_ATTRIBUTE_PTR tobject_get_attribute_full(tobject *tobj, CK_ATTRIBUTE_PTR attr); 92 | 93 | CK_RV tobject_get_min_buf_size(tobject *tobj, CK_MECHANISM_PTR mech, size_t *maxsize); 94 | 95 | CK_RV object_mech_is_supported(tobject *tobj, CK_MECHANISM_PTR mech); 96 | 97 | /** 98 | * Gets the attributes for a tobject. If it's a link to a tobject, follows it 99 | * and retrieves the public attributes, as the link object is the public portion. 100 | * Else, it's not the link object and retrieves the private attributes. 101 | * @param tobj 102 | * The tobject to fetch the attributes from. 103 | * @return 104 | * The attribute array. 105 | */ 106 | attr_list *tobject_get_attrs(tobject *tobj); 107 | 108 | CK_RV _tobject_user_decrement(tobject *tobj, const char *filename, int lineno); 109 | CK_RV _tobject_user_increment(tobject *tobj, const char *filename, int lineno); 110 | 111 | /** 112 | * Marks a tobject no longer being used by an operation. 113 | * 114 | * @param tobj 115 | * The tobject to retire. 116 | * @return 117 | * CKR_OK on success, CKR_GENERAL_ERROR if not active. 118 | */ 119 | #define tobject_user_decrement(tobj) _tobject_user_decrement(tobj, __FILE__, __LINE__) 120 | 121 | /** 122 | * Marks a tobject as in use by an operation. 123 | * 124 | * @param tobj 125 | * The tobject to mark as in use. 126 | * @return 127 | * CKR_OK on success, CKR_GENERAL_ERROR if not active. 128 | */ 129 | #define tobject_user_increment(tobj) _tobject_user_increment(tobj, __FILE__, __LINE__) 130 | 131 | CK_RV object_destroy(session_ctx *ctx, CK_OBJECT_HANDLE object); 132 | 133 | 134 | CK_RV object_create(session_ctx *ctx, CK_ATTRIBUTE *templ, CK_ULONG count, CK_OBJECT_HANDLE *object); 135 | 136 | WEAK CK_RV object_init_from_attrs(tobject *tobj); 137 | 138 | #ifdef TESTING 139 | tobject *__real_tobject_new(void); 140 | void pobject_free(pobject *pobj); 141 | #endif 142 | 143 | #endif /* SRC_PKCS11_OBJECT_H_ */ 144 | -------------------------------------------------------------------------------- /src/lib/parser.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #ifndef SRC_LIB_PARSER_H_ 3 | #define SRC_LIB_PARSER_H_ 4 | 5 | #include 6 | 7 | #include "attrs.h" 8 | #include "debug.h" 9 | #include "pkcs11.h" 10 | #include "token.h" 11 | 12 | WEAK bool parse_attributes_from_string(const unsigned char *yaml, size_t size, 13 | attr_list **attrs); 14 | 15 | bool parse_token_config_from_string(const unsigned char *yaml, size_t size, 16 | token_config *config); 17 | 18 | bool parse_pobject_config_from_string(const unsigned char *yaml, size_t size, 19 | pobject_config *config); 20 | 21 | #endif /* SRC_LIB_PARSER_H_ */ 22 | -------------------------------------------------------------------------------- /src/lib/random.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #include "checks.h" 4 | #include "pkcs11.h" 5 | #include "random.h" 6 | #include "session_ctx.h" 7 | #include "token.h" 8 | #include "tpm.h" 9 | 10 | CK_RV random_get(session_ctx *ctx, CK_BYTE_PTR random_data, CK_ULONG random_len) { 11 | 12 | check_pointer(random_data); 13 | 14 | token *tok = session_ctx_get_token(ctx); 15 | assert(tok); 16 | 17 | tpm_ctx *tpm = tok->tctx; 18 | 19 | bool res = tpm_getrandom(tpm, random_data, random_len); 20 | 21 | return res ? CKR_OK: CKR_GENERAL_ERROR; 22 | } 23 | 24 | CK_RV seed_random(session_ctx *ctx, CK_BYTE_PTR seed, CK_ULONG seed_len) { 25 | 26 | check_pointer(seed); 27 | 28 | token *tok = session_ctx_get_token(ctx); 29 | assert(tok); 30 | 31 | tpm_ctx *tpm = tok->tctx; 32 | CK_RV rv = tpm_stirrandom(tpm, seed, seed_len); 33 | 34 | return rv; 35 | } 36 | -------------------------------------------------------------------------------- /src/lib/random.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef SRC_PKCS11_RANDOM_H_ 4 | #define SRC_PKCS11_RANDOM_H_ 5 | 6 | #include "pkcs11.h" 7 | #include "session_ctx.h" 8 | 9 | typedef struct token token; 10 | typedef struct session_ctx session_ctx; 11 | 12 | CK_RV random_get(session_ctx *ctx, unsigned char *random_data, unsigned long random_len); 13 | 14 | CK_RV seed_random(session_ctx *ctx, unsigned char *seed, unsigned long seed_len); 15 | 16 | #endif /* SRC_PKCS11_RANDOM_H_ */ 17 | -------------------------------------------------------------------------------- /src/lib/session.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "checks.h" 8 | #include "general.h" 9 | #include "log.h" 10 | #include "mutex.h" 11 | #include "pkcs11.h" 12 | #include "session.h" 13 | #include "session_table.h" 14 | #include "token.h" 15 | #include "tpm.h" 16 | #include "utils.h" 17 | 18 | static CK_RV check_max_sessions(session_table *s_table) { 19 | 20 | CK_ULONG all; 21 | 22 | session_table_get_cnt(s_table, &all, NULL, NULL); 23 | 24 | return (all > MAX_NUM_OF_SESSIONS) ? 25 | CKR_SESSION_COUNT : CKR_OK; 26 | } 27 | 28 | #define TOKID_SESSION_SHIFT ((sizeof(CK_SESSION_HANDLE) * 8) - 8) 29 | 30 | static inline void add_tokid_to_session_handle(unsigned tokid, 31 | CK_SESSION_HANDLE *handle) { 32 | 33 | /* 34 | * Plop the token id in the high byte 35 | */ 36 | *handle |= ((typeof(*handle))tokid << TOKID_SESSION_SHIFT); 37 | } 38 | 39 | static inline unsigned get_tokid_from_session_handle_and_cleanse( 40 | CK_SESSION_HANDLE *handle) { 41 | 42 | /* 43 | * Get the token id from the high byte 44 | */ 45 | unsigned tokid = (*handle >> TOKID_SESSION_SHIFT); 46 | 47 | /* 48 | * drop the top byte, this is a simple way to deal 49 | * with CK_SESSION_HANDLE being architecture dependent 50 | * in size. 51 | */ 52 | CK_SESSION_HANDLE tmp = *handle; 53 | tmp = tmp << 8; 54 | tmp = tmp >> 8; 55 | *handle = tmp; 56 | 57 | return tokid; 58 | } 59 | 60 | CK_RV session_open(CK_SLOT_ID slot_id, CK_FLAGS flags, void *application, 61 | CK_NOTIFY notify, CK_SESSION_HANDLE *session) { 62 | 63 | (void) notify; 64 | (void) application; /* can be null */ 65 | 66 | if (!(flags & CKF_SERIAL_SESSION)) { 67 | return CKR_SESSION_PARALLEL_NOT_SUPPORTED; 68 | } 69 | 70 | CK_RV rv = CKR_GENERAL_ERROR; 71 | 72 | check_pointer(session); 73 | 74 | token *t = slot_get_token(slot_id); 75 | if (!t) { 76 | return CKR_SLOT_ID_INVALID; 77 | } 78 | 79 | rv = check_max_sessions(t->s_table); 80 | if (rv != CKR_OK) { 81 | return rv; 82 | } 83 | 84 | /* 85 | * Cannot open an R/O session when the SO is logged in 86 | */ 87 | if ((!(flags & CKF_RW_SESSION)) && (t->login_state == token_so_logged_in)) { 88 | return CKR_SESSION_READ_WRITE_SO_EXISTS; 89 | } 90 | 91 | rv = session_table_new_entry(t->s_table, session, t, flags); 92 | if (rv != CKR_OK) { 93 | return rv; 94 | } 95 | 96 | add_tokid_to_session_handle(t->id, session); 97 | 98 | return CKR_OK; 99 | } 100 | 101 | CK_RV session_close(CK_SESSION_HANDLE session) { 102 | 103 | token *t = NULL; 104 | unsigned tokid = get_tokid_from_session_handle_and_cleanse(&session); 105 | check_slot_id(tokid, t, CKR_SESSION_HANDLE_INVALID); 106 | 107 | return session_table_free_ctx(t, session); 108 | } 109 | 110 | CK_RV session_closeall(CK_SLOT_ID slot_id) { 111 | 112 | token *t; 113 | check_slot_id(slot_id, t, CKR_SLOT_ID_INVALID); 114 | 115 | return session_table_free_ctx_all(t); 116 | } 117 | 118 | CK_RV session_lookup(CK_SESSION_HANDLE session, token **tok, session_ctx **ctx) { 119 | 120 | token *tmp = NULL; 121 | unsigned tokid = get_tokid_from_session_handle_and_cleanse(&session); 122 | check_slot_id(tokid, tmp, CKR_SESSION_HANDLE_INVALID); 123 | 124 | *ctx = session_table_lookup(tmp->s_table, session); 125 | if (!*ctx) { 126 | return CKR_SESSION_HANDLE_INVALID; 127 | } 128 | 129 | token_lock(tmp); 130 | 131 | *tok = tmp; 132 | 133 | return CKR_OK; 134 | } 135 | -------------------------------------------------------------------------------- /src/lib/session.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef SRC_PKCS11_SESSION_H_ 4 | #define SRC_PKCS11_SESSION_H_ 5 | 6 | #include 7 | 8 | #include "pkcs11.h" 9 | #include "tpm.h" 10 | 11 | typedef struct session_ctx session_ctx; 12 | typedef struct token token; 13 | 14 | /* 15 | * This max value CANNOT extend into the upper byte of a CK_SESSION_HANDLE, 16 | * as that is reserved for the tokid. 17 | */ 18 | #define MAX_NUM_OF_SESSIONS 1024 19 | 20 | CK_RV session_open(CK_SLOT_ID slot_id, CK_FLAGS flags, void *application, 21 | CK_NOTIFY notify, CK_SESSION_HANDLE *session); 22 | 23 | CK_RV session_close(CK_SESSION_HANDLE session); 24 | 25 | CK_RV session_closeall(CK_SLOT_ID slot_id); 26 | 27 | CK_RV session_lookup(CK_SESSION_HANDLE session, token **tok, session_ctx **ctx); 28 | 29 | #endif /* SRC_PKCS11_SESSION_H_ */ 30 | -------------------------------------------------------------------------------- /src/lib/session_table.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #include "config.h" 4 | #include 5 | #include 6 | 7 | #include "mutex.h" 8 | #include "pkcs11.h" 9 | #include "session_ctx.h" 10 | #include "session_table.h" 11 | #include "token.h" 12 | #include "utils.h" 13 | 14 | struct session_table { 15 | CK_ULONG cnt; 16 | CK_ULONG rw_cnt; 17 | session_ctx *table[MAX_NUM_OF_SESSIONS]; 18 | }; 19 | 20 | CK_RV session_table_new(session_table **t) { 21 | 22 | session_table *x = calloc(1, sizeof(session_table)); 23 | if (!x) { 24 | return CKR_HOST_MEMORY; 25 | } 26 | 27 | *t = x; 28 | 29 | return CKR_OK; 30 | } 31 | 32 | void session_table_free(session_table *t) { 33 | 34 | if (!t) { 35 | return; 36 | } 37 | 38 | free(t); 39 | } 40 | 41 | void session_table_get_cnt(session_table *t, CK_ULONG_PTR all, CK_ULONG_PTR rw, CK_ULONG_PTR ro) { 42 | 43 | /* All counts should always be greater than or equal to rw count */ 44 | assert(t->cnt >= t->rw_cnt); 45 | 46 | if (all) { 47 | *all = t->cnt; 48 | } 49 | 50 | if (rw) { 51 | *rw = t->rw_cnt; 52 | } 53 | 54 | if (ro) { 55 | *ro = t->cnt - t->rw_cnt; 56 | } 57 | } 58 | 59 | CK_RV session_table_new_entry(session_table *t, CK_SESSION_HANDLE *handle, 60 | token *tok, CK_FLAGS flags) { 61 | 62 | CK_SESSION_HANDLE free_handle = 0; 63 | session_ctx **open_slot = NULL; 64 | size_t i; 65 | for (i=0; i < ARRAY_LEN(t->table); i++) { 66 | if (!t->table[i]) { 67 | /* 0 is not a good session handle, so offset by 1 */ 68 | free_handle = i + 1; 69 | open_slot = &t->table[i]; 70 | break; 71 | } 72 | } 73 | 74 | if (!open_slot) { 75 | LOGV("No available session slot found"); 76 | return CKR_SESSION_COUNT; 77 | } 78 | 79 | CK_RV rv = session_ctx_new(open_slot, tok, flags); 80 | if (rv != CKR_OK) { 81 | return rv; 82 | } 83 | 84 | *handle = free_handle; 85 | t->cnt++; 86 | 87 | if(flags & CKF_RW_SESSION) { 88 | t->rw_cnt++; 89 | } 90 | 91 | return CKR_OK; 92 | } 93 | 94 | static CK_RV do_logout_if_needed(session_ctx *ctx) { 95 | 96 | token *tok = session_ctx_get_token(ctx); 97 | assert(tok); 98 | 99 | if (tok->login_state == token_no_one_logged_in) { 100 | return CKR_OK; 101 | } 102 | 103 | return session_ctx_logout(ctx); 104 | } 105 | 106 | static CK_RV session_table_free_ctx_by_ctx(token *t, session_ctx **ctx) { 107 | 108 | session_table *stable = t->s_table; 109 | 110 | CK_RV rv = CKR_OK; 111 | 112 | CK_STATE state = session_ctx_state_get(*ctx); 113 | if(state == CKS_RW_PUBLIC_SESSION 114 | || state == CKS_RW_USER_FUNCTIONS 115 | || state == CKS_RW_SO_FUNCTIONS) { 116 | assert(stable->rw_cnt); 117 | stable->rw_cnt--; 118 | } 119 | 120 | stable->cnt--; 121 | 122 | /* Per the spec, when session count hits 0, logout */ 123 | if (!stable->cnt) { 124 | rv = do_logout_if_needed(*ctx); 125 | if (rv != CKR_OK) { 126 | LOGE("do_logout_if_needed failed: 0x%lx", rv); 127 | } 128 | } 129 | 130 | session_ctx_free(*ctx); 131 | 132 | *ctx = NULL; 133 | 134 | return rv; 135 | } 136 | 137 | static session_ctx **_session_table_lookup(session_table *t, CK_SESSION_HANDLE handle) { 138 | 139 | if (handle == 0 || handle > ARRAY_LEN(t->table)) { 140 | return NULL; 141 | } 142 | 143 | return &t->table[handle - 1]; 144 | } 145 | 146 | session_ctx *session_table_lookup(session_table *t, CK_SESSION_HANDLE handle) { 147 | 148 | return *_session_table_lookup(t, handle); 149 | } 150 | 151 | CK_RV session_table_free_ctx_by_handle(token *t, CK_SESSION_HANDLE handle) { 152 | 153 | session_ctx **ctx = _session_table_lookup(t->s_table, handle); 154 | if (!*ctx) { 155 | return CKR_SESSION_HANDLE_INVALID; 156 | } 157 | 158 | return session_table_free_ctx_by_ctx(t, ctx); 159 | } 160 | 161 | CK_RV session_table_free_ctx_all(token *t) { 162 | 163 | bool had_error = false; 164 | 165 | if (!t->s_table) { 166 | return CKR_OK; 167 | } 168 | 169 | unsigned i; 170 | for (i=0; i < ARRAY_LEN(t->s_table->table); i++) { 171 | CK_SESSION_HANDLE handle = i; 172 | 173 | /* 174 | * skip dead handles 175 | */ 176 | session_ctx **ctx = &t->s_table->table[handle]; 177 | if (!*ctx) { 178 | continue; 179 | } 180 | 181 | CK_RV rv = session_table_free_ctx_by_ctx(t, ctx); 182 | if (rv != CKR_OK) { 183 | LOGE("Failed to free session_ctx: 0x%lx", rv); 184 | had_error = true; 185 | } 186 | } 187 | 188 | return !had_error ? CKR_OK : CKR_GENERAL_ERROR; 189 | } 190 | 191 | CK_RV session_table_free_ctx(token *t, CK_SESSION_HANDLE handle) { 192 | 193 | return session_table_free_ctx_by_handle(t, handle); 194 | } 195 | 196 | void session_table_login_event(session_table *s_table, CK_USER_TYPE user) { 197 | 198 | size_t i; 199 | for (i=0; i < ARRAY_LEN(s_table->table); i++) { 200 | 201 | session_ctx *ctx = s_table->table[i]; 202 | if (!ctx) { 203 | continue; 204 | } 205 | 206 | session_ctx_login_event(ctx, user); 207 | } 208 | } 209 | 210 | void token_logout_all_sessions(token *tok) { 211 | 212 | size_t i; 213 | for (i=0; i < ARRAY_LEN(tok->s_table->table); i++) { 214 | 215 | session_ctx *ctx = tok->s_table->table[i]; 216 | if (!ctx) { 217 | continue; 218 | } 219 | 220 | session_ctx_logout_event(ctx); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /src/lib/session_table.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef SRC_PKCS11_SESSION_TABLE_H_ 4 | #define SRC_PKCS11_SESSION_TABLE_H_ 5 | 6 | #include "session.h" 7 | #include "session_ctx.h" 8 | #include "session_table.h" 9 | 10 | typedef struct token token; 11 | 12 | typedef struct session_table session_table; 13 | 14 | CK_RV session_table_new(session_table **t); 15 | void session_table_free(session_table *t); 16 | 17 | void session_table_get_cnt(session_table *t, unsigned long *all, unsigned long *rw, unsigned long *ro); 18 | 19 | CK_RV session_table_new_entry(session_table *t, 20 | CK_SESSION_HANDLE *handle, token *tok, CK_FLAGS flags); 21 | 22 | session_ctx *session_table_lookup(session_table *t, CK_SESSION_HANDLE handle); 23 | 24 | CK_RV session_table_free_ctx_by_handle(token *t, CK_SESSION_HANDLE handle); 25 | CK_RV session_table_free_ctx(token *t, CK_SESSION_HANDLE handle); 26 | CK_RV session_table_free_ctx_all(token *t); 27 | 28 | /** 29 | * performs a session_ctx_login_event() call for each item in the table 30 | * with the session table lock held. 31 | * @param s_table 32 | * The session table 33 | * @param user 34 | * The user triggering the login event. 35 | */ 36 | void session_table_login_event(session_table *s_table, CK_USER_TYPE user); 37 | 38 | /** 39 | * performs a session_ctx_logout_event() call for each item in the table 40 | * with the session table lock held. 41 | * @param s_table 42 | * The session table 43 | * @param called_session 44 | * The session context that the logout event occurred on. 45 | */ 46 | void token_logout_all_sessions(token *tok); 47 | 48 | 49 | #endif /* SRC_PKCS11_SESSION_TABLE_H_ */ 50 | -------------------------------------------------------------------------------- /src/lib/sign.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef _SRC_LIB_SIGN_H_ 4 | #define _SRC_LIB_SIGN_H_ 5 | 6 | #include "pkcs11.h" 7 | #include "session_ctx.h" 8 | 9 | CK_RV sign_init(session_ctx *ctx, CK_MECHANISM *mechanism, CK_OBJECT_HANDLE key); 10 | 11 | CK_RV sign_update(session_ctx *ctx, unsigned char *part, unsigned long part_len); 12 | 13 | CK_RV sign_final_ex(session_ctx *ctx, unsigned char *signature, unsigned long *signature_len, bool is_oneshot); 14 | 15 | static inline CK_RV sign_final(session_ctx *ctx, unsigned char *signature, unsigned long *signature_len) { 16 | return sign_final_ex(ctx, signature, signature_len, false); 17 | } 18 | 19 | CK_RV sign(session_ctx *ctx, unsigned char *data, unsigned long data_len, unsigned char *signature, unsigned long *signature_len); 20 | 21 | CK_RV verify_init(session_ctx *ctx, CK_MECHANISM *mechanism, CK_OBJECT_HANDLE key); 22 | 23 | CK_RV verify_update(session_ctx *ctx, unsigned char *part, unsigned long part_len); 24 | 25 | CK_RV verify_final(session_ctx *ctx, unsigned char *signature, unsigned long signature_len); 26 | 27 | CK_RV verify(session_ctx *ctx, unsigned char *data, unsigned long data_len, unsigned char *signature, unsigned long signature_len); 28 | 29 | CK_RV verify_recover_init (session_ctx *ctx, CK_MECHANISM *mechanism, CK_OBJECT_HANDLE key); 30 | 31 | CK_RV verify_recover (session_ctx *ctx, CK_BYTE_PTR signature, CK_ULONG signature_len, 32 | CK_BYTE_PTR data, CK_ULONG_PTR data_len); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/lib/slot.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #include 4 | #include 5 | 6 | #include "checks.h" 7 | #include "backend.h" 8 | #include "mech.h" 9 | #include "pkcs11.h" 10 | #include "slot.h" 11 | #include "token.h" 12 | #include "utils.h" 13 | 14 | static struct { 15 | size_t token_cnt; 16 | token *token; 17 | void *mutex; 18 | } global; 19 | 20 | CK_RV slot_init(void) { 21 | 22 | CK_RV rv = mutex_create(&global.mutex); 23 | if (rv != CKR_OK) { 24 | return rv; 25 | } 26 | 27 | return backend_get_tokens(&global.token, &global.token_cnt); 28 | } 29 | 30 | static void slot_lock(void) { 31 | mutex_lock_fatal(global.mutex); 32 | } 33 | 34 | static void slot_unlock(void) { 35 | mutex_unlock_fatal(global.mutex); 36 | } 37 | 38 | void slot_destroy(void) { 39 | 40 | token_free_list(&global.token, &global.token_cnt); 41 | 42 | CK_RV rv = mutex_destroy(global.mutex); 43 | global.mutex = NULL; 44 | if (rv != CKR_OK) { 45 | LOGW("Failed to destroy mutex"); 46 | } 47 | } 48 | 49 | token *slot_get_token(CK_SLOT_ID slot_id) { 50 | 51 | slot_lock(); 52 | 53 | size_t i; 54 | for (i=0; i < global.token_cnt; i++) { 55 | token *t = &global.token[i]; 56 | if (slot_id == t->id) { 57 | slot_unlock(); 58 | return t; 59 | } 60 | } 61 | 62 | slot_unlock(); 63 | return NULL; 64 | } 65 | 66 | CK_RV slot_get_list (CK_BYTE token_present, CK_SLOT_ID *slot_list, CK_ULONG_PTR count) { 67 | 68 | /* 69 | * True for token present only returns slots with tokens, False all slots. All 70 | * of our slots always have a token, so we can ignore this. 71 | */ 72 | UNUSED(token_present); 73 | 74 | check_pointer(count); 75 | 76 | slot_lock(); 77 | 78 | if (!slot_list) { 79 | slot_unlock(); 80 | *count = global.token_cnt; 81 | return CKR_OK; 82 | } 83 | 84 | if (*count < global.token_cnt) { 85 | *count = global.token_cnt; 86 | slot_unlock(); 87 | return CKR_BUFFER_TOO_SMALL; 88 | } 89 | 90 | size_t i; 91 | for (i=0; i < global.token_cnt; i++) { 92 | token *t = &global.token[i]; 93 | slot_list[i] = t->id; 94 | } 95 | 96 | *count = global.token_cnt; 97 | 98 | slot_unlock(); 99 | 100 | return CKR_OK; 101 | } 102 | 103 | CK_RV slot_get_info (CK_SLOT_ID slot_id, CK_SLOT_INFO *info) { 104 | 105 | token *token; 106 | 107 | check_pointer(info); 108 | 109 | token = slot_get_token(slot_id); 110 | if (!token) { 111 | return CKR_SLOT_ID_INVALID; 112 | } 113 | 114 | token_lock(token); 115 | 116 | CK_TOKEN_INFO token_info; 117 | if (token_get_info(token, &token_info)) { 118 | token_unlock(token); 119 | return CKR_GENERAL_ERROR; 120 | } 121 | 122 | str_padded_copy(info->manufacturerID, token_info.manufacturerID); 123 | str_padded_copy(info->slotDescription, token_info.label); 124 | 125 | info->hardwareVersion = token_info.hardwareVersion; 126 | info->firmwareVersion = token_info.firmwareVersion; 127 | 128 | info->flags = CKF_TOKEN_PRESENT | CKF_HW_SLOT; 129 | 130 | token_unlock(token); 131 | return CKR_OK; 132 | } 133 | 134 | 135 | CK_RV slot_mechanism_list_get (CK_SLOT_ID slot_id, CK_MECHANISM_TYPE *mechanism_list, CK_ULONG_PTR count) { 136 | 137 | token *t = slot_get_token(slot_id); 138 | if (!t) { 139 | return CKR_SLOT_ID_INVALID; 140 | } 141 | 142 | token_lock(t); 143 | CK_RV rv = mech_get_supported(t->mdtl, mechanism_list, count); 144 | token_unlock(t); 145 | return rv; 146 | } 147 | 148 | CK_RV slot_mechanism_info_get (CK_SLOT_ID slot_id, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO *info) { 149 | 150 | check_pointer(info); 151 | 152 | token *t = slot_get_token(slot_id); 153 | if (!t) { 154 | return CKR_SLOT_ID_INVALID; 155 | } 156 | 157 | token_lock(t); 158 | 159 | CK_RV rv = mech_get_info(t->mdtl, t->tctx, type, info); 160 | if (rv != CKR_OK) { 161 | token_unlock(t); 162 | return rv; 163 | } 164 | 165 | token_unlock(t); 166 | 167 | return CKR_OK; 168 | } 169 | 170 | CK_RV slot_add_uninit_token(void) { 171 | 172 | CK_RV rv = CKR_GENERAL_ERROR; 173 | 174 | slot_lock(); 175 | 176 | if (global.token_cnt < MAX_TOKEN_CNT) { 177 | 178 | size_t i; 179 | for (i=0; i < global.token_cnt; i++) { 180 | token *t = &global.token[i]; 181 | if (!t->config.is_initialized) { 182 | LOGV("Skipping adding uninitialized token, one found"); 183 | rv = CKR_OK; 184 | goto out; 185 | } 186 | } 187 | 188 | token *t = &global.token[global.token_cnt++]; 189 | t->id = global.token_cnt; 190 | rv = token_min_init(t); 191 | if (rv != CKR_OK) { 192 | goto out; 193 | } 194 | 195 | assert(t->id); 196 | } else { 197 | LOGW("Reached max tokens in store"); 198 | } 199 | 200 | rv = CKR_OK; 201 | 202 | out: 203 | slot_unlock(); 204 | return rv; 205 | } 206 | -------------------------------------------------------------------------------- /src/lib/slot.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef SRC_SLOT_H_ 4 | #define SRC_SLOT_H_ 5 | 6 | #include 7 | 8 | #include "pkcs11.h" 9 | 10 | typedef struct token token; 11 | 12 | #define SLOT_ID 0x1234 13 | 14 | CK_RV slot_init(void); 15 | void slot_destroy(void); 16 | 17 | token *slot_get_token(CK_SLOT_ID slot_id); 18 | 19 | CK_RV slot_get_list (unsigned char token_present, CK_SLOT_ID *slot_list, unsigned long *count); 20 | CK_RV slot_get_info (CK_SLOT_ID slot_id, CK_SLOT_INFO *info); 21 | CK_RV slot_mechanism_list_get (CK_SLOT_ID slotID, CK_MECHANISM_TYPE *mechanism_list, unsigned long *count); 22 | CK_RV slot_mechanism_info_get (CK_SLOT_ID slot_id, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO *info); 23 | CK_RV slot_add_uninit_token(void); 24 | 25 | #endif /* SRC_SLOT_H_ */ 26 | -------------------------------------------------------------------------------- /src/lib/ssl_util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #ifndef SRC_LIB_SSL_UTIL_H_ 3 | #define SRC_LIB_SSL_UTIL_H_ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "pkcs11.h" 13 | 14 | #include "attrs.h" 15 | #include "log.h" 16 | #include "twist.h" 17 | 18 | #if (OPENSSL_VERSION_NUMBER >= 0x1010100fL) /* OpenSSL 1.1.1 */ 19 | #define LIB_TPM2_OPENSSL_OPENSSL_POST111 0x1010100f 20 | #endif 21 | 22 | #if defined(LIB_TPM2_OPENSSL_OPENSSL_POST111) 23 | #include 24 | #endif 25 | 26 | #if (OPENSSL_VERSION_NUMBER >= 0x30000000) /* OpenSSL 3.0.0 */ 27 | #define LIB_TPM2_OPENSSL_OPENSSL_POST300 0x1010100f 28 | #endif 29 | 30 | #define SSL_UTIL_LOGE(m) LOGE("%s: %s", m, ERR_error_string(ERR_get_error(), NULL)); 31 | 32 | CK_RV ssl_util_attrs_to_evp(attr_list *attrs, EVP_PKEY **outpkey); 33 | 34 | CK_RV ssl_util_encrypt(EVP_PKEY *pkey, 35 | int padding, twist label, const EVP_MD *md, 36 | CK_BYTE_PTR ptext, CK_ULONG ptextlen, 37 | CK_BYTE_PTR ctext, CK_ULONG_PTR ctextlen); 38 | 39 | CK_RV ssl_util_sig_verify(EVP_PKEY *pkey, 40 | int padding, const EVP_MD *md, 41 | CK_BYTE_PTR digest, CK_ULONG digest_len, 42 | CK_BYTE_PTR signature, CK_ULONG signature_len); 43 | 44 | CK_RV ssl_util_verify_recover(EVP_PKEY *pkey, 45 | int padding, const EVP_MD *md, 46 | CK_BYTE_PTR signature, CK_ULONG signature_len, 47 | CK_BYTE_PTR data, CK_ULONG_PTR data_len); 48 | 49 | typedef int (*fn_EVP_PKEY_init)(EVP_PKEY_CTX *ctx); 50 | 51 | CK_RV ssl_util_setup_evp_pkey_ctx(EVP_PKEY *pkey, 52 | int padding, const EVP_MD *md, 53 | fn_EVP_PKEY_init init_fn, 54 | EVP_PKEY_CTX **outpkey_ctx); 55 | 56 | CK_RV ssl_util_add_PKCS1_PSS(EVP_PKEY *pkey, 57 | const CK_BYTE_PTR inbuf, const EVP_MD *md, 58 | CK_BYTE_PTR outbuf); 59 | 60 | CK_RV ssl_util_add_PKCS1_TYPE_1(const CK_BYTE_PTR inbuf, CK_ULONG inlen, 61 | CK_BYTE_PTR outbuf, CK_ULONG outbuflen); 62 | 63 | CK_RV ssl_util_check_PKCS1_TYPE_2(const CK_BYTE_PTR inbuf, CK_ULONG inlen, CK_ULONG rsa_len, 64 | CK_BYTE_PTR outbuf, CK_ULONG_PTR outbuflen); 65 | 66 | twist ssl_util_hash_pass(const twist pin, const twist salt); 67 | 68 | /** 69 | * Given an attribute of CKA_EC_PARAMS returns the nid value. 70 | * @param ecparams 71 | * The DER X9.62 parameters value 72 | * @param nid 73 | * The nid to set 74 | * @return 75 | * CKR_OK on success. 76 | */ 77 | CK_RV ssl_util_params_to_nid(CK_ATTRIBUTE_PTR ecparams, int *nid); 78 | 79 | #endif /* SRC_LIB_SSL_UTIL_H_ */ 80 | -------------------------------------------------------------------------------- /src/lib/typed_memory.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #include "pkcs11.h" 8 | #include "typed_memory.h" 9 | #include "utils.h" 10 | 11 | void *type_calloc(size_t nmemb, size_t size, CK_BYTE type) { 12 | 13 | assert(size != 0); 14 | 15 | size_t total = 0; 16 | safe_mul(total, nmemb, size); 17 | safe_adde(total, 1); 18 | 19 | CK_BYTE_PTR ptr = (CK_BYTE_PTR)calloc(1, total); 20 | if (!ptr) { 21 | return NULL; 22 | } 23 | 24 | ptr[total - 1] = type; 25 | 26 | return ptr; 27 | } 28 | 29 | void *type_zrealloc(void *old_ptr, size_t size, CK_BYTE type) { 30 | 31 | assert(size != 0); 32 | 33 | // overflow safety here... 34 | size_t total = size + 1; 35 | 36 | CK_BYTE_PTR new_ptr = realloc(old_ptr, total); 37 | if (!new_ptr) { 38 | return NULL; 39 | } 40 | 41 | memset(new_ptr, 0, total); 42 | 43 | new_ptr[total - 1] = type; 44 | 45 | return new_ptr; 46 | } 47 | 48 | 49 | 50 | CK_BYTE type_from_ptr(void *ptr, size_t len) { 51 | 52 | if (!len || !ptr) { 53 | return TYPE_BYTE_HEX_STR; 54 | } 55 | 56 | CK_BYTE_PTR b = (CK_BYTE_PTR)ptr; 57 | return b[len]; 58 | } 59 | 60 | CK_RV type_mem_dup(void *in, size_t len, void **dup) { 61 | 62 | CK_BYTE type = in ? 63 | type_from_ptr(in, len) : TYPE_BYTE_HEX_STR; 64 | 65 | assert(type != 0); 66 | 67 | void *buf = type_calloc(1, len, type); 68 | if (!buf) { 69 | return CKR_HOST_MEMORY; 70 | } 71 | 72 | if (in) { 73 | memcpy(buf, in, len); 74 | } 75 | 76 | *dup = buf; 77 | 78 | #ifndef NDEBUG 79 | CK_BYTE check = type_from_ptr(buf, len); 80 | assert(check == type); 81 | #endif 82 | return CKR_OK; 83 | } 84 | 85 | void type_mem_cpy(void *dest, void *in, size_t size) { 86 | assert(in); 87 | assert(dest); 88 | assert(size); 89 | safe_adde(size, 1); 90 | memcpy(dest, in, size); 91 | #ifndef NDEBUG 92 | CK_BYTE check = type_from_ptr(in, size - 1); 93 | CK_BYTE got = type_from_ptr(dest, size - 1); 94 | assert(check == got); 95 | #endif 96 | } 97 | 98 | const char *type_to_str(CK_BYTE type) { 99 | 100 | switch(type) { 101 | case TYPE_BYTE_INT: 102 | return "int"; 103 | case TYPE_BYTE_BOOL: 104 | return "bool"; 105 | case TYPE_BYTE_INT_SEQ: 106 | return "int-seq"; 107 | case TYPE_BYTE_HEX_STR: 108 | return "hex-str"; 109 | default: 110 | return "unknown"; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/lib/typed_memory.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #ifndef SRC_LIB_TYPED_MEMORY_H_ 3 | #define SRC_LIB_TYPED_MEMORY_H_ 4 | 5 | #define TYPE_BYTE_INT ((CK_BYTE)1) 6 | #define TYPE_BYTE_BOOL ((CK_BYTE)2) 7 | #define TYPE_BYTE_INT_SEQ ((CK_BYTE)3) 8 | #define TYPE_BYTE_HEX_STR ((CK_BYTE)4) 9 | /* 10 | * if we ever need wrap templates we will define a special type. 11 | * The parser would also need to be updated to recognize a seq 12 | * of attribute template pointers. 13 | */ 14 | #define TYPE_BYTE_TEMP_SEQ ((CK_BYTE)5) 15 | 16 | void *type_calloc(size_t nmemb, size_t size, CK_BYTE type); 17 | void *type_zrealloc(void *ptr, size_t size, CK_BYTE type); 18 | 19 | CK_BYTE type_from_ptr(void *ptr, size_t len); 20 | CK_RV type_mem_dup(void *in, size_t len, void **dup); 21 | void type_mem_cpy(void *dest, void *in, size_t size); 22 | const char *type_to_str(CK_BYTE type); 23 | 24 | #endif /* SRC_LIB_TYPED_MEMORY_H_ */ 25 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-2-Clause 2 | # Test Artifacts 3 | *.trs 4 | *.log 5 | *.pid 6 | test_pkcs11 7 | test_twist 8 | -------------------------------------------------------------------------------- /test/fuzz/db-take-lock.fuzz.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #include "config.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include "db.h" 18 | 19 | static const uint8_t *_data; 20 | static size_t _size; 21 | 22 | typedef struct test_state test_state; 23 | struct test_state { 24 | char *random_string; 25 | char *tmp_dir; 26 | FILE *file; 27 | }; 28 | 29 | static inline test_state *test_state_cast(void **state) { 30 | return (test_state *)*state; 31 | } 32 | 33 | static void test_state_free(test_state **test) { 34 | 35 | if (test && *test) { 36 | test_state *t = *test; 37 | free(t->random_string); 38 | if (t->file) { 39 | fclose(t->file); 40 | } 41 | free(t); 42 | *test = NULL; 43 | } 44 | } 45 | 46 | static test_state *test_state_new(const uint8_t *data, size_t len) { 47 | 48 | /* require a null terminated string */ 49 | char *null_term_data = calloc(1, len + 1); 50 | if (!null_term_data) { 51 | return NULL; 52 | } 53 | memcpy(null_term_data, data, len); 54 | 55 | char tmp_key[] = "pkcs11_fuzztest_db_take_lock_XXXXXX"; 56 | char *tmp_dir = mkdtemp(tmp_key); 57 | if (!tmp_dir) { 58 | free(null_term_data); 59 | return NULL; 60 | } 61 | 62 | test_state *t = calloc(1, sizeof(test_state)); 63 | if (!t) { 64 | free(null_term_data); 65 | return NULL; 66 | } 67 | 68 | t->random_string = null_term_data; 69 | t->tmp_dir = tmp_dir; 70 | 71 | return t; 72 | } 73 | 74 | static int setup(void **state) { 75 | 76 | /* assign to state */ 77 | *state = test_state_new(_data, _size); 78 | 79 | return *state == NULL; 80 | } 81 | 82 | static int teardown(void **state) { 83 | 84 | test_state *s = test_state_cast(state); 85 | test_state_free(&s); 86 | 87 | return 0; 88 | } 89 | 90 | static void test(void **state) { 91 | 92 | test_state *t = test_state_cast(state); 93 | assert_non_null(t); 94 | 95 | setenv("PKCS11_SQL_LOCK", t->random_string, true); 96 | 97 | char lockpath[PATH_MAX]; 98 | t->file = take_lock(t->tmp_dir, lockpath); 99 | } 100 | 101 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 102 | 103 | _size = size; 104 | _data = data; 105 | 106 | const struct CMUnitTest tests[] = { 107 | cmocka_unit_test_setup_teardown(test, setup, teardown), 108 | }; 109 | 110 | cmocka_run_group_tests(tests, NULL, NULL); 111 | return 0; 112 | } 113 | -------------------------------------------------------------------------------- /test/fuzz/db-token-label.fuzz32.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #include "config.h" 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "db.h" 10 | #include "token.h" 11 | #include "pkcs11.h" 12 | 13 | #include "wrap_tpm.h" 14 | 15 | static const uint8_t *_data; 16 | static size_t _size; 17 | 18 | static sqlite3 *_db; 19 | static token _token; 20 | 21 | /* hidden api */ 22 | extern CK_RV db_init_new(sqlite3 *db); 23 | extern void db_debug_set_db(sqlite3 *db); 24 | 25 | /* overriding weak symbol, like wrap */ 26 | CK_RV db_new(sqlite3 **db) { 27 | 28 | *db = _db; 29 | return CKR_OK; 30 | } 31 | 32 | /* overriding weak symbol, like wrap */ 33 | void db_get_label(token *t, sqlite3_stmt *stmt, int iCol) { 34 | UNUSED(stmt); 35 | UNUSED(iCol); 36 | 37 | /* FUZZ DATA */ 38 | memcpy(t->label, _data, _size); 39 | } 40 | 41 | static int setup(void **state) { 42 | UNUSED(state); 43 | 44 | set_default_tpm(); 45 | 46 | int rc = sqlite3_open(":memory:", &_db); 47 | assert_int_equal(rc, SQLITE_OK); 48 | 49 | CK_RV rv = db_init_new(_db); 50 | assert_int_equal(rv, CKR_OK); 51 | 52 | db_debug_set_db(_db); 53 | 54 | unsigned int pid = 0; 55 | pobject pobj = { 0 }; 56 | pobj.config.blob = twist_new("aabbccdd"); 57 | assert_non_null(pobj.config.blob); 58 | rv = db_add_primary(&pobj, &pid); 59 | twist_free(pobj.config.blob); 60 | assert_int_equal(rv, CKR_OK); 61 | 62 | /* create and add a dummy token */ 63 | memcpy(_token.label, "foo", 3); 64 | _token.pid = pid; 65 | 66 | _token.config.is_initialized = true; 67 | 68 | _token.esysdb.sealobject.sopriv = twist_new("sopriv"); 69 | assert_non_null(_token.esysdb.sealobject.sopriv); 70 | 71 | _token.esysdb.sealobject.soauthsalt = twist_new("soauthsalt"); 72 | assert_non_null(_token.esysdb.sealobject.soauthsalt); 73 | 74 | _token.esysdb.sealobject.sopub = twist_new("sopub"); 75 | assert_non_null(_token.esysdb.sealobject.sopub); 76 | 77 | _token.esysdb.sealobject.userauthsalt = twist_new("userauthsalt"); 78 | assert_non_null(_token.esysdb.sealobject.userauthsalt); 79 | 80 | rv = db_add_token(&_token); 81 | assert_int_equal(rv, CKR_OK); 82 | 83 | setenv("TPM2_PKCS11_STORE", ":memory:", 1); 84 | 85 | rv = C_Initialize(NULL); 86 | assert_int_equal(rv, CKR_OK); 87 | 88 | return 0; 89 | } 90 | 91 | static int teardown(void **state) { 92 | UNUSED(state); 93 | 94 | set_default_tpm(); 95 | 96 | CK_RV rv = C_Finalize(NULL); 97 | assert_int_equal(rv, CKR_OK); 98 | 99 | token_free(&_token); 100 | 101 | return 0; 102 | } 103 | 104 | static void test(void **state) { 105 | UNUSED(state); 106 | 107 | /* nothing to do, setup and teardown do it */ 108 | CK_SLOT_ID slot_ids[2]; 109 | CK_ULONG cnt = ARRAY_LEN(slot_ids); 110 | CK_RV rv = C_GetSlotList(true, slot_ids, &cnt); 111 | assert_int_equal(rv, CKR_OK); 112 | 113 | CK_TOKEN_INFO info; 114 | /* FUZZ TARGET */ 115 | rv = C_GetTokenInfo(slot_ids[0], &info); 116 | assert_int_equal(rv, CKR_OK); 117 | } 118 | 119 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 120 | 121 | if (size > 32) { 122 | LOGE("SIZE BIGGER THAN 32"); 123 | return 0; 124 | } 125 | 126 | _size = size; 127 | _data = data; 128 | 129 | const struct CMUnitTest tests[] = { 130 | cmocka_unit_test_setup_teardown(test, setup, teardown), 131 | }; 132 | 133 | cmocka_run_group_tests(tests, NULL, NULL); 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /test/fuzz/init-pin.fuzz.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #include "config.h" 3 | 4 | #include 5 | #include 6 | 7 | #include "attrs.h" 8 | #include "log.h" 9 | #include "parser.h" 10 | #include "pkcs11.h" 11 | 12 | #include "wrap_tpm.h" 13 | 14 | static const uint8_t *_data; 15 | static size_t _size; 16 | static CK_SESSION_HANDLE _session; 17 | 18 | static int setup(void **state) { 19 | UNUSED(state); 20 | 21 | /* 22 | * we just use an in memory db so we don't need to fake sqlite or deal 23 | * 24 | * with temp file cleanup 25 | */ 26 | setenv("TPM2_PKCS11_STORE", ":memory:", 1); 27 | set_default_tpm(); 28 | 29 | CK_RV rv = C_Initialize(NULL); 30 | assert_int_equal(rv, CKR_OK); 31 | 32 | CK_SLOT_ID slot_list; 33 | CK_ULONG count = 1; 34 | 35 | rv = C_GetSlotList(0, &slot_list, &count); 36 | assert_int_equal(rv, CKR_OK); 37 | assert_int_not_equal(count, 0); 38 | 39 | CK_BYTE label[32] = " my label"; 40 | rv = C_InitToken(slot_list, (CK_BYTE_PTR)"mysopin", 7, label); 41 | assert_int_equal(rv, CKR_OK); 42 | 43 | rv = C_OpenSession(slot_list, CKF_SERIAL_SESSION | CKF_RW_SESSION, 44 | NULL, NULL, &_session); 45 | assert_int_equal(rv, CKR_OK); 46 | 47 | rv = C_Login(_session, CKU_SO, (CK_BYTE_PTR)"mysopin", 7); 48 | assert_int_equal(rv, CKR_OK); 49 | 50 | return 0; 51 | } 52 | 53 | static int teardown(void **state) { 54 | UNUSED(state); 55 | 56 | set_default_tpm(); 57 | 58 | CK_RV rv = C_Finalize(NULL); 59 | assert_int_equal(rv, CKR_OK); 60 | 61 | return 0; 62 | } 63 | 64 | static void test(void **state) { 65 | UNUSED(state); 66 | 67 | set_default_tpm(); 68 | 69 | /* FUZZ TARGET C_InitPIN pin */ 70 | CK_RV rv = C_InitPIN(_session, (CK_BYTE_PTR)_data, _size); 71 | /* it should never fail, all pins are ok */ 72 | assert_int_equal(rv, CKR_OK); 73 | } 74 | 75 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 76 | 77 | _size = size; 78 | _data = data; 79 | 80 | const struct CMUnitTest tests[] = { 81 | cmocka_unit_test_setup_teardown(test, setup, teardown), 82 | }; 83 | 84 | cmocka_run_group_tests(tests, NULL, NULL); 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /test/fuzz/init-token-label.fuzz32.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #include "config.h" 3 | 4 | #include 5 | #include 6 | 7 | #include "attrs.h" 8 | #include "log.h" 9 | #include "parser.h" 10 | #include "pkcs11.h" 11 | 12 | #include "wrap_tpm.h" 13 | 14 | static CK_BYTE _label[32]; 15 | 16 | static void test(void **state) { 17 | UNUSED(state); 18 | 19 | /* 20 | * we just use an in memory db so we don't need to fake sqlite or deal 21 | * 22 | * with temp file cleanup 23 | */ 24 | setenv("TPM2_PKCS11_STORE", ":memory:", 1); 25 | 26 | will_return_maybe(__wrap_backend_fapi_init, CKR_GENERAL_ERROR); 27 | will_return_maybe(__wrap_Esys_Initialize, TSS2_RC_SUCCESS); 28 | will_return_maybe(__wrap_Tss2_TctiLdr_Initialize, TSS2_RC_SUCCESS); 29 | will_return_maybe(__wrap_Tss2_TctiLdr_Finalize, TSS2_RC_SUCCESS); 30 | will_return_maybe(__wrap_Esys_Finalize, TSS2_RC_SUCCESS); 31 | will_return_maybe(__wrap_Esys_TR_FromTPMPublic, TSS2_RC_SUCCESS); 32 | will_return_maybe(__wrap_Esys_TR_Serialize, TSS2_RC_SUCCESS); 33 | will_return_maybe(__wrap_Esys_TR_SetAuth, TSS2_RC_SUCCESS); 34 | will_return_maybe(__wrap_Esys_StartAuthSession, TSS2_RC_SUCCESS); 35 | will_return_maybe(__wrap_Esys_TRSess_SetAttributes, TSS2_RC_SUCCESS); 36 | will_return_maybe(__wrap_Esys_Create, TSS2_RC_SUCCESS); 37 | will_return_maybe(__wrap_Esys_FlushContext, TSS2_RC_SUCCESS); 38 | 39 | CK_RV rv = C_Initialize(NULL); 40 | assert_int_equal(rv, CKR_OK); 41 | 42 | CK_SLOT_ID slot_list; 43 | CK_ULONG count = 1; 44 | 45 | rv = C_GetSlotList(0, &slot_list, &count); 46 | assert_int_equal(rv, CKR_OK); 47 | assert_int_not_equal(count, 0); 48 | 49 | /* FUZZ TARGET C_InitToken LABEL */ 50 | rv = C_InitToken(slot_list, (CK_BYTE_PTR)"mysopin", 7, _label); 51 | /* some may work some may fail do not check RV */ 52 | 53 | rv = C_Finalize(NULL); 54 | assert_int_equal(rv, CKR_OK); 55 | } 56 | 57 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 58 | 59 | if (size > sizeof(_label)) { 60 | LOGE("Size is not valid, expected less than %zu got: %zu", 61 | sizeof(_label), size); 62 | abort(); 63 | } 64 | 65 | /* lets just throw random 32 byte buffers at it and see what blows up */ 66 | memcpy(_label, data, size); 67 | 68 | const struct CMUnitTest tests[] = { 69 | cmocka_unit_test(test), 70 | }; 71 | 72 | cmocka_run_group_tests(tests, NULL, NULL); 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /test/fuzz/init-token-sopin.fuzz.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #include "config.h" 3 | 4 | #include 5 | #include 6 | 7 | #include "attrs.h" 8 | #include "log.h" 9 | #include "parser.h" 10 | #include "pkcs11.h" 11 | 12 | #include "wrap_tpm.h" 13 | 14 | static const uint8_t *_data = NULL; 15 | static size_t _size = 0; 16 | 17 | static void test(void **state) { 18 | UNUSED(state); 19 | 20 | /* 21 | * we just use an in memory db so we don't need to fake sqlite or deal 22 | * 23 | * with temp file cleanup 24 | */ 25 | setenv("TPM2_PKCS11_STORE", ":memory:", 1); 26 | 27 | will_return_always(__wrap_backend_fapi_init, CKR_GENERAL_ERROR); 28 | will_return_always(__wrap_Esys_Initialize, TSS2_RC_SUCCESS); 29 | will_return_always(__wrap_Tss2_TctiLdr_Initialize, TSS2_RC_SUCCESS); 30 | will_return_always(__wrap_Tss2_TctiLdr_Finalize, TSS2_RC_SUCCESS); 31 | //will_return_always(__wrap_Esys_GetCapability, TSS2_RC_SUCCESS); 32 | will_return_always(__wrap_Esys_Finalize, TSS2_RC_SUCCESS); 33 | will_return_always(__wrap_Esys_TR_FromTPMPublic, TSS2_RC_SUCCESS); 34 | will_return_always(__wrap_Esys_TR_Serialize, TSS2_RC_SUCCESS); 35 | // will_return_always(__wrap_Esys_TR_Deserialize, TSS2_RC_SUCCESS); 36 | will_return_always(__wrap_Esys_TR_SetAuth, TSS2_RC_SUCCESS); 37 | will_return_always(__wrap_Esys_StartAuthSession, TSS2_RC_SUCCESS); 38 | // will_return_always(__wrap_Esys_TRSess_GetAttributes, TSS2_RC_SUCCESS); 39 | will_return_always(__wrap_Esys_TRSess_SetAttributes, TSS2_RC_SUCCESS); 40 | // will_return_always(__wrap_Esys_CreateLoaded, TSS2_RC_SUCCESS); 41 | will_return_always(__wrap_Esys_Create, TSS2_RC_SUCCESS); 42 | will_return_always(__wrap_Esys_FlushContext, TSS2_RC_SUCCESS); 43 | 44 | CK_RV rv = C_Initialize(NULL); 45 | assert_int_equal(rv, CKR_OK); 46 | 47 | CK_SLOT_ID slot_list; 48 | CK_ULONG count = 1; 49 | 50 | rv = C_GetSlotList(0, &slot_list, &count); 51 | assert_int_equal(rv, CKR_OK); 52 | assert_int_not_equal(count, 0); 53 | 54 | CK_BYTE label[32] = " my label"; 55 | 56 | /* FUZZ TARGET C_InitToken SOPIN */ 57 | rv = C_InitToken(slot_list, (CK_BYTE_PTR)_data, _size, label); 58 | /* any pin should work */ 59 | assert_int_equal(rv, CKR_OK); 60 | 61 | rv = C_Finalize(NULL); 62 | assert_int_equal(rv, CKR_OK); 63 | } 64 | 65 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 66 | 67 | _data = data; 68 | _size = size; 69 | 70 | const struct CMUnitTest tests[] = { 71 | cmocka_unit_test(test), 72 | }; 73 | 74 | cmocka_run_group_tests(tests, NULL, NULL); 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /test/fuzz/scripts/fuzz-runner.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | set -u 4 | set +o nounset 5 | set -x 6 | 7 | # see: 8 | # - https://stackoverflow.com/questions/1215538/extract-parameters-before-last-parameter-in 9 | # for details on this. it moves the last argument (the fuzz-target) to the front and the 10 | # AM_FUZZ_LOG_FLAGS after the executable fuzz target...whew. 11 | env ${@:$#} ${*%${!#}} 12 | 13 | exit $? 14 | -------------------------------------------------------------------------------- /test/fuzz/set-pin.fuzz.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #include "config.h" 3 | 4 | #include 5 | #include 6 | 7 | #include "attrs.h" 8 | #include "log.h" 9 | #include "parser.h" 10 | #include "pkcs11.h" 11 | 12 | #include "wrap_tpm.h" 13 | 14 | static const uint8_t *_data; 15 | static size_t _size; 16 | static CK_SESSION_HANDLE _session; 17 | 18 | static int setup(void **state) { 19 | UNUSED(state); 20 | 21 | /* 22 | * we just use an in memory db so we don't need to fake sqlite or deal 23 | * 24 | * with temp file cleanup 25 | */ 26 | setenv("TPM2_PKCS11_STORE", ":memory:", 1); 27 | set_default_tpm(); 28 | 29 | CK_RV rv = C_Initialize(NULL); 30 | assert_int_equal(rv, CKR_OK); 31 | 32 | CK_SLOT_ID slot_list; 33 | CK_ULONG count = 1; 34 | 35 | rv = C_GetSlotList(0, &slot_list, &count); 36 | assert_int_equal(rv, CKR_OK); 37 | assert_int_not_equal(count, 0); 38 | 39 | CK_BYTE label[32] = " my label"; 40 | rv = C_InitToken(slot_list, (CK_BYTE_PTR)"mysopin", 7, label); 41 | assert_int_equal(rv, CKR_OK); 42 | 43 | rv = C_OpenSession(slot_list, CKF_SERIAL_SESSION | CKF_RW_SESSION, 44 | NULL, NULL, &_session); 45 | assert_int_equal(rv, CKR_OK); 46 | 47 | rv = C_Login(_session, CKU_SO, (CK_BYTE_PTR)"mysopin", 7); 48 | assert_int_equal(rv, CKR_OK); 49 | 50 | rv = C_InitPIN(_session, (CK_BYTE_PTR)"myuserpin", 9); 51 | assert_int_equal(rv, CKR_OK); 52 | 53 | return 0; 54 | } 55 | 56 | static int teardown(void **state) { 57 | UNUSED(state); 58 | 59 | set_default_tpm(); 60 | 61 | CK_RV rv = C_Finalize(NULL); 62 | assert_int_equal(rv, CKR_OK); 63 | 64 | return 0; 65 | } 66 | 67 | static void test(void **state) { 68 | UNUSED(state); 69 | 70 | set_default_tpm(); 71 | 72 | /* FUZZ TARGET C_InitPIN pin */ 73 | CK_RV rv = C_SetPIN(_session, (CK_BYTE_PTR)"mysopin", 7, 74 | (CK_BYTE_PTR)_data, _size); 75 | /* it should never fail, all pins are ok */ 76 | assert_int_equal(rv, CKR_OK); 77 | } 78 | 79 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 80 | 81 | _size = size; 82 | _data = data; 83 | 84 | const struct CMUnitTest tests[] = { 85 | cmocka_unit_test_setup_teardown(test, setup, teardown), 86 | }; 87 | 88 | cmocka_run_group_tests(tests, NULL, NULL); 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /test/fuzz/utils-ctx-unwrap-objauth.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include "token.h" 16 | #include "twist.h" 17 | #include "utils.h" 18 | 19 | static const uint8_t *_data = NULL; 20 | static size_t _size = 0; 21 | 22 | /* 23 | * We want to target malicious DB injection. If someone points us to a store, 24 | * where data is malformed, we want to tolerate that. 25 | * 26 | * Generally 3 things come from the db in wild formats: 27 | * 1. attributes in yaml 28 | * 2. wrapped object auths (immediately handed to twistbin_new()) 29 | * 3. Public and Private TPM blobs 30 | * 31 | * This test aims to check issue 2. 32 | * 33 | * Sample Good Corpus with key below: 34 | * 05271d7286bfb46667a6ed2c:aa1f228f9925ac9694663d0b20dc5526:a8b8b5487e1abe7585458e88c8c7e82dc8c1f40d7bb0c6776a3895ecf75d240b 35 | * 36 | * Define CORPUS_TEST to test it. 37 | */ 38 | static void test(void **state) { 39 | UNUSED(state); 40 | #ifdef CORPUS_TEST 41 | char *e = "05271d7286bfb46667a6ed2c:aa1f228f9925ac9694663d0b20dc5526:a8b8b5487e1abe7585458e88c8c7e82dc8c1f40d7bb0c6776a3895ecf75d240b"; 42 | _data = (uint8_t *)e; 43 | _size = strlen(e); 44 | #endif 45 | 46 | /* we just need an AES key, any key will work */ 47 | twist wrappingkey = twistbin_unhexlify("6ef4c48c59793d6f004dbf4de399e643b627031a4bfd352b660fadaced95c9b4"); 48 | assert_non_null(wrappingkey); 49 | 50 | twist wrapped = twistbin_new(_data, _size); 51 | assert_non_null(wrapped); 52 | 53 | twist unwrapped = NULL; 54 | /* 55 | * under the hood this expects very specifically formatted hex data, make sure that code 56 | * doesn't blow up 57 | */ 58 | CK_RV rv = utils_ctx_unwrap_objauth(wrappingkey, wrapped, &unwrapped); 59 | #ifdef CORPUS_TEST 60 | assert_int_equal(rv, CKR_OK); 61 | #else 62 | UNUSED(rv); 63 | #endif 64 | 65 | twist_free(wrappingkey); 66 | twist_free(wrapped); 67 | twist_free(unwrapped); 68 | } 69 | 70 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 71 | 72 | _data = data; 73 | _size = size; 74 | 75 | const struct CMUnitTest tests[] = { 76 | cmocka_unit_test(test), 77 | }; 78 | 79 | cmocka_run_group_tests(tests, NULL, NULL); 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /test/fuzz/yaml-parser.fuzz.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #include "config.h" 3 | #include "debug.h" 4 | 5 | /* 6 | * Drop WEAK or the parse_attributes_from_string is NULL 7 | * This command below will be empty without this. I am not 8 | * 100% sure why its not getting resolved properly, but this 9 | * fixes it for now. 10 | * nm --defined ./test/fuzz/yaml-parser.fuzz | grep parse 11 | 00000000005558d0 T parse_attributes_from_string 12 | */ 13 | #undef WEAK 14 | #define WEAK 15 | 16 | #include 17 | #include 18 | 19 | #include "attrs.h" 20 | #include "parser.h" 21 | 22 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 23 | 24 | attr_list *attrs = NULL; 25 | 26 | parse_attributes_from_string(data, size, 27 | &attrs); 28 | attr_list_free(attrs); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /test/integration/.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-2-Clause 2 | *.int 3 | -------------------------------------------------------------------------------- /test/integration/PKCS11JavaTests.java: -------------------------------------------------------------------------------- 1 | import java.io.ByteArrayInputStream; 2 | import java.io.InputStream; 3 | /* Introspection to support Java < 9 */ 4 | import java.lang.reflect.Constructor; 5 | import java.lang.reflect.Method; 6 | import java.nio.file.Path; 7 | import java.nio.file.Paths; 8 | import java.security.Key; 9 | import java.security.KeyStore; 10 | import java.security.PrivateKey; 11 | import java.security.Provider; 12 | import java.security.PublicKey; 13 | import java.security.Security; 14 | import java.security.Signature; 15 | import java.security.cert.X509Certificate; 16 | 17 | import javax.crypto.Cipher; 18 | 19 | import org.junit.Assert; 20 | import org.junit.BeforeClass; 21 | import org.junit.Test; 22 | import org.junit.runner.JUnitCore; 23 | import org.junit.runner.Result; 24 | import org.junit.runner.notification.Failure; 25 | 26 | public class PKCS11JavaTests { 27 | 28 | static final String PIN = "myuserpin"; 29 | static final String KEY_ALIAS = "rsa1"; 30 | 31 | static KeyStore KEY_STORE; 32 | static Provider PROV; 33 | 34 | @BeforeClass 35 | public static void beforeAllTestMethods() throws Exception { 36 | /* 37 | * Generate a new provider to use the SUNPKCS11 module 38 | * 39 | */ 40 | String cwd = System.getProperty("user.dir"); 41 | Path libPath = Paths.get(cwd, "src/.libs/libtpm2_pkcs11.so.0.0.0"); 42 | 43 | String version = System.getProperty("java.version"); 44 | /* Parse for example "11.0.11" or "17-ea" */ 45 | String [] chunks = version.split("[\\.-]"); 46 | int major = Integer.parseInt(chunks[0]); 47 | if (major >= 9) { 48 | /* Java >= 9 */ 49 | Method configure = Provider.class.getMethod("configure", String.class); 50 | String pkcs11Config = "--name = TPM2\nlibrary = " + libPath; 51 | PROV = Security.getProvider("SunPKCS11"); 52 | PROV = (Provider) configure.invoke(PROV, pkcs11Config); 53 | } else { 54 | /* Java <= 8 */ 55 | Constructor SunPKCS11 = Class.forName("sun.security.pkcs11.SunPKCS11").getConstructor(InputStream.class); 56 | String pkcs11Config = "name = TPM2\nlibrary = " + libPath; 57 | ByteArrayInputStream confStream = new ByteArrayInputStream(pkcs11Config.getBytes()); 58 | PROV = (Provider) SunPKCS11.newInstance(confStream); 59 | } 60 | 61 | /* add the provider */ 62 | Security.addProvider(PROV); 63 | 64 | /* Generate a keystore from the provider */ 65 | KEY_STORE = KeyStore.getInstance("PKCS11-TPM2"); 66 | KeyStore.PasswordProtection pp = new KeyStore.PasswordProtection(PIN.toCharArray()); 67 | KEY_STORE.load(null, pp.getPassword()); 68 | } 69 | 70 | @Test 71 | public void test_rsa_crypto() throws Exception { 72 | 73 | /* Get the key/cert pair */ 74 | Key rsaKey = KEY_STORE.getKey(KEY_ALIAS, null); 75 | Assert.assertEquals("RSA", rsaKey.getAlgorithm()); 76 | 77 | X509Certificate certificate = (X509Certificate) KEY_STORE.getCertificate(KEY_ALIAS); 78 | 79 | /* get the public key from the cert */ 80 | Key rsaPublicKey = certificate.getPublicKey(); 81 | 82 | /* Encrypt public decrypt private */ 83 | Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", PROV); 84 | 85 | String plaintext = "mysecretdata"; 86 | 87 | byte[] plainData = plaintext.getBytes("UTF-8"); 88 | 89 | cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey); 90 | byte[] encryptedData = cipher.doFinal(plainData); 91 | 92 | cipher.init(Cipher.DECRYPT_MODE, rsaKey); 93 | int output = cipher.getOutputSize(encryptedData.length); 94 | byte[] decryptedData = cipher.doFinal(encryptedData); 95 | 96 | Assert.assertArrayEquals(plainData, decryptedData); 97 | 98 | /* Encrypt private decrypt public */ 99 | cipher.init(Cipher.ENCRYPT_MODE, rsaKey); 100 | encryptedData = cipher.doFinal(plainData); 101 | 102 | cipher.init(Cipher.DECRYPT_MODE, rsaPublicKey); 103 | output = cipher.getOutputSize(encryptedData.length); 104 | decryptedData = cipher.doFinal(encryptedData); 105 | } 106 | 107 | @Test 108 | public void test_signverify_signature() throws Exception { 109 | 110 | /* Get the key/cert pair */ 111 | Key rsaKey = KEY_STORE.getKey(KEY_ALIAS, null); 112 | Assert.assertEquals("RSA", rsaKey.getAlgorithm()); 113 | 114 | X509Certificate certificate = (X509Certificate) KEY_STORE.getCertificate(KEY_ALIAS); 115 | 116 | /* get the public key from the cert */ 117 | Key rsaPublicKey = certificate.getPublicKey(); 118 | 119 | /* Sign private Verify public */ 120 | Signature signature = Signature.getInstance("SHA256withRSA", PROV); 121 | 122 | String plaintext = "mysecretdata"; 123 | 124 | byte[] plainData = plaintext.getBytes("UTF-8"); 125 | 126 | signature.initSign((PrivateKey) rsaKey); 127 | signature.update(plainData); 128 | byte[] signedData = signature.sign(); 129 | 130 | signature.initVerify((PublicKey) rsaPublicKey); 131 | signature.update(plainData); 132 | 133 | boolean retSignature = signature.verify(signedData); 134 | Assert.assertTrue(retSignature); 135 | } 136 | 137 | public static void main(String[] args) { 138 | int rc = 1; 139 | Result result = JUnitCore.runClasses(PKCS11JavaTests.class); 140 | if (result.wasSuccessful()) { 141 | rc = 0; 142 | System.out.println("Success"); 143 | } else { 144 | System.out.println("Failed"); 145 | } 146 | 147 | for (Failure failure : result.getFailures()) { 148 | System.out.println(failure.toString()); 149 | } 150 | 151 | System.exit(rc); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /test/integration/fixtures/client.cnf: -------------------------------------------------------------------------------- 1 | [ ca ] 2 | default_ca = CA_default 3 | 4 | [ CA_default ] 5 | fixtures = $ENV::TEST_FIXTURES 6 | dir = $ENV::CA_DIR 7 | certs = $dir 8 | crl_dir = $dir/crl 9 | database = $dir/index.txt 10 | new_certs_dir = $dir 11 | certificate = $dir/ca.pem 12 | serial = $dir/serial 13 | crl = $dir/crl.pem 14 | private_key = $dir/ca.key 15 | name_opt = ca_default 16 | cert_opt = ca_default 17 | default_days = 60 18 | default_crl_days = 30 19 | default_md = sha256 20 | preserve = no 21 | policy = policy_match 22 | 23 | [ policy_match ] 24 | countryName = match 25 | stateOrProvinceName = match 26 | organizationName = match 27 | organizationalUnitName = optional 28 | commonName = supplied 29 | emailAddress = optional 30 | 31 | [ policy_anything ] 32 | countryName = optional 33 | stateOrProvinceName = optional 34 | localityName = optional 35 | organizationName = optional 36 | organizationalUnitName = optional 37 | commonName = supplied 38 | emailAddress = optional 39 | 40 | [ req ] 41 | prompt = no 42 | distinguished_name = client 43 | default_bits = 2048 44 | input_password = whatever 45 | output_password = whatever 46 | 47 | [client] 48 | countryName = US 49 | stateOrProvinceName = Radius 50 | localityName = Somewhere 51 | organizationName = Example Inc. 52 | emailAddress = user@example.org 53 | commonName = user@example.org 54 | -------------------------------------------------------------------------------- /test/integration/fixtures/hmac.hex.key: -------------------------------------------------------------------------------- 1 | 0336aa7945a3cadec3cbdc6e79043b5b -------------------------------------------------------------------------------- /test/integration/fixtures/ossl-req-ca.cnf: -------------------------------------------------------------------------------- 1 | # OpenSSL configuration for generating CA certificates 2 | [req] 3 | default_bits = 2048 4 | req_extensions = ca_ext 5 | distinguished_name = ca_dn 6 | 7 | [ca_dn] 8 | commonName = "Test CA" 9 | 10 | [ca_ext] 11 | keyUsage = critical,keyCertSign,cRLSign 12 | basicConstraints = critical,CA:true 13 | subjectKeyIdentifier = hash 14 | -------------------------------------------------------------------------------- /test/integration/fixtures/ossl-req-cert.cnf: -------------------------------------------------------------------------------- 1 | # OpenSSL configuration for generating a certificate signed by a CA 2 | [req] 3 | default_bits = 2048 4 | req_extensions = cert_ext 5 | distinguished_name = dn 6 | 7 | [dn] 8 | commonName = "Test Certificate" 9 | 10 | [cert_ext] 11 | keyUsage = critical,digitalSignature 12 | basicConstraints = critical,CA:false 13 | subjectKeyIdentifier = hash 14 | -------------------------------------------------------------------------------- /test/integration/fixtures/ossl.cnf: -------------------------------------------------------------------------------- 1 | openssl_conf = openssl_init 2 | 3 | [openssl_init] 4 | engines = engine_section 5 | 6 | [engine_section] 7 | pkcs11 = pkcs11_section 8 | 9 | [pkcs11_section] 10 | engine_id = pkcs11 11 | MODULE_PATH = ${ENV::TPM2_PKCS11_MODULE} 12 | PIN=myuserpin 13 | init = 0 14 | 15 | [ req ] 16 | distinguished_name = req_dn 17 | string_mask = utf8only 18 | utf8 = yes 19 | 20 | [ req_dn ] 21 | commonName = Mr Test Harness 22 | -------------------------------------------------------------------------------- /test/integration/fixtures/smimeextensions: -------------------------------------------------------------------------------- 1 | [smime] 2 | basicConstraints = critical,CA:FALSE 3 | keyUsage = nonRepudiation, digitalSignature, keyEncipherment 4 | subjectKeyIdentifier = hash 5 | authorityKeyIdentifier = keyid,issuer 6 | subjectAltName = email:move 7 | extendedKeyUsage = emailProtection 8 | -------------------------------------------------------------------------------- /test/integration/fixtures/tss2engine.cnf: -------------------------------------------------------------------------------- 1 | openssl_conf = openssl_init 2 | 3 | [openssl_init] 4 | engines = engine_section 5 | 6 | [engine_section] 7 | tpm2tss = tpm2tss_section 8 | 9 | [tpm2tss_section] 10 | SET_TCTI = ${ENV::TPM2_PKCS11_TCTI} 11 | -------------------------------------------------------------------------------- /test/integration/fixtures/xpextensions: -------------------------------------------------------------------------------- 1 | # 2 | # File containing the OIDs required for Windows. 3 | # 4 | # http://support.microsoft.com/kb/814394/en-us 5 | # 6 | [ xpclient_ext] 7 | extendedKeyUsage = 1.3.6.1.5.5.7.3.2 8 | crlDistributionPoints = URI:http://www.example.com/example_ca.crl 9 | 10 | [ xpserver_ext] 11 | extendedKeyUsage = 1.3.6.1.5.5.7.3.1 12 | crlDistributionPoints = URI:http://www.example.com/example_ca.crl 13 | 14 | # 15 | # Add this to the PKCS#7 keybag attributes holding the client's private key 16 | # for machine authentication. 17 | # 18 | # the presence of this OID tells Windows XP that the cert is intended 19 | # for use by the computer itself, and not by an end-user. 20 | # 21 | # The other solution is to use Microsoft's web certificate server 22 | # to generate these certs. 23 | # 24 | # 1.3.6.1.4.1.311.17.2 25 | -------------------------------------------------------------------------------- /test/integration/openssl.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | 4 | set -exo pipefail 5 | 6 | if [ -z "$T" ]; then 7 | export T="$(cd "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)" 8 | fi 9 | 10 | source "$T/test/integration/scripts/helpers.sh" 11 | 12 | # Don't test with OSSL3, since we dont have an engine to call us through, 13 | # we would have to port everything over to the provider, which then doesn't 14 | # test tpm2-pkcs11 code anyways. 15 | check_openssl_version 16 | if [ "$OSSL3_DETECTED" -eq "1" ]; then 17 | exit 77 18 | fi 19 | 20 | 21 | PIN="myuserpin" 22 | token_label="label" 23 | key_label="rsa1" 24 | 25 | function cleanup() { 26 | rm -f objlist.yaml key.attrs.yaml certificate.der.hex certificate.der certificate.pem \ 27 | pubkey.pem data.txt 28 | } 29 | trap cleanup EXIT 30 | 31 | onerror() { 32 | echo "$BASH_COMMAND on line ${BASH_LINENO[0]} failed: $?" 33 | exit 1 34 | } 35 | trap onerror ERR 36 | 37 | cleanup 38 | 39 | setup_asan 40 | 41 | if [ -z "$modpath" ]; then 42 | modpath="$PWD/src/.libs/libtpm2_pkcs11.so" 43 | fi 44 | 45 | echo "modpath=$modpath" 46 | 47 | function yaml_get_id() { 48 | 49 | "${PYTHON_INTERPRETER:-python3}" << pyscript 50 | from __future__ import print_function 51 | 52 | import sys 53 | import yaml 54 | 55 | with open("$1") as f: 56 | try: 57 | y = yaml.load(f, Loader=yaml.BaseLoader) 58 | 59 | for x in y: 60 | if x['CKA_LABEL'] == "$2" and x['CKA_CLASS'] == "$3": 61 | print(x['id']) 62 | except yaml.YAMLError as exc: 63 | sys.exit(exc) 64 | pyscript 65 | } 66 | 67 | function yaml_get_kv() { 68 | 69 | third_arg="" 70 | if [ $# -eq 3 ]; then 71 | third_arg=$3 72 | fi 73 | 74 | "${PYTHON_INTERPRETER:-python3}" << pyscript 75 | from __future__ import print_function 76 | 77 | import sys 78 | import yaml 79 | 80 | with open("$1") as f: 81 | try: 82 | y = yaml.load(f, Loader=yaml.BaseLoader) 83 | if $# == 3: 84 | print(y["$2"]["$third_arg"]) 85 | else: 86 | print(y["$2"]) 87 | except yaml.YAMLError as exc: 88 | sys.exit(exc) 89 | pyscript 90 | } 91 | 92 | pkcs11_tool() { 93 | pkcs11-tool --module "$modpath" "$@" 94 | return $? 95 | } 96 | 97 | # step 1 is to get the id by listing the objects 98 | tpm2_ptool listobjects --label="$token_label" > "objlist.yaml" 99 | 100 | cert_db_id=$(yaml_get_id objlist.yaml "$key_label" CKO_CERTIFICATE) 101 | 102 | echo "cert db id: $cert_db_id" 103 | 104 | tpm2_ptool objmod --id="$cert_db_id" > "key.attrs.yaml" 105 | 106 | # 17 is the raw attribute value for CKA_VALUE which contains the certificate 107 | yaml_get_kv "key.attrs.yaml" 17 > "certificate.der.hex" 108 | 109 | # 258 is CKA_ID, get the key id 110 | cka_id_hex=$(yaml_get_kv "key.attrs.yaml" 258) 111 | 112 | # convert the hex to binary 113 | cat "certificate.der.hex" | xxd -p -r > "certificate.der" 114 | 115 | # convert to a pem, which helps verify the der 116 | openssl x509 -inform DER -in "certificate.der" -outform PEM -out "certificate.pem" 117 | 118 | # extract the pubkey 119 | openssl x509 -pubkey -noout -in "certificate.pem" > "pubkey.pem" 120 | 121 | # do an rsa-pss signature on data 122 | echo "sig data" > "data.txt" 123 | 124 | export OPENSSL_CONF="$TEST_FIXTURES/ossl.cnf" 125 | 126 | PKCS11_KEY="pkcs11:model=SW%20%20%20TPM;manufacturer=IBM;serial=0000000000000000;token=$token_label;object=$key_label;type=private" 127 | 128 | openssl dgst -engine pkcs11 -keyform engine -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -sign "$PKCS11_KEY" -out data.sig data.txt 129 | 130 | openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -signature data.sig -verify pubkey.pem data.txt 131 | 132 | rm data.sig 133 | 134 | # The above for me always takes the raw signing path, either via C_Sign or C_Encrypt interfaces. So we will use pkcs11tool to force it 135 | # pkcs11tool is dumb, even though --label should be the object label, it only really is coded to know --id. 136 | # A bug in older OpenSC versions (like 0.15.0), map the _PSS identifiers wrong except for SHA1. This bug was fixed in OpenSC in: 137 | # https://github.com/OpenSC/OpenSC/pull/1146 138 | # 139 | # Their is no generic way to really figure out the OpenSC version AFAICT to we code this to the common denominator of SHA1 140 | pkcs11_tool --pin "$PIN" --token-label "$token_label" --id "$cka_id_hex" --sign --mechanism SHA1-RSA-PKCS-PSS -i data.txt -o data.sig 141 | 142 | openssl dgst -sha1 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -signature data.sig -verify pubkey.pem data.txt 143 | 144 | rm data.sig 145 | 146 | # verify that importing certificates do not modify them 147 | # NB. OpenSSL never verified the signature of self-signed certificate: 148 | # https://github.com/openssl/openssl/blob/openssl-3.0.0/ssl/t1_lib.c#L2970 149 | # This is why two certificates are needed 150 | cert_db_id="$(yaml_get_id objlist.yaml rsa1 CKO_CERTIFICATE)" 151 | tpm2_ptool objmod --id="$cert_db_id" > "key.attrs.yaml" 152 | yaml_get_kv "key.attrs.yaml" 17 | xxd -p -r > "ca.der" 153 | openssl x509 -inform DER -in "ca.der" -outform PEM -out "ca.pem" 154 | cert_db_id="$(yaml_get_id objlist.yaml rsa2 CKO_CERTIFICATE)" 155 | tpm2_ptool objmod --id="$cert_db_id" > "key.attrs.yaml" 156 | yaml_get_kv "key.attrs.yaml" 17 | xxd -p -r > "cert.der" 157 | openssl x509 -inform DER -in "cert.der" -outform PEM -out "cert.pem" 158 | openssl verify -CAfile ca.pem cert.pem 159 | 160 | exit 0 161 | -------------------------------------------------------------------------------- /test/integration/p11-tool-fapi.sh.fapi: -------------------------------------------------------------------------------- 1 | p11-tool.sh.nosetup -------------------------------------------------------------------------------- /test/integration/pkcs-session-state.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #include "test.h" 4 | 5 | struct test_info { 6 | CK_SLOT_ID slot; 7 | CK_OBJECT_HANDLE key; 8 | CK_SESSION_HANDLE session[2]; 9 | }; 10 | 11 | static test_info *test_info_new(void) { 12 | 13 | test_info *ti = calloc(1, sizeof(*ti)); 14 | assert_non_null(ti); 15 | 16 | CK_SLOT_ID slots[6]; 17 | CK_ULONG count = ARRAY_LEN(slots); 18 | CK_RV rv = C_GetSlotList(true, slots, &count); 19 | assert_int_equal(rv, CKR_OK); 20 | 21 | rv = C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION, 22 | NULL, NULL, &ti->session[0]); 23 | assert_int_equal(rv, CKR_OK); 24 | 25 | rv = C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION, 26 | NULL, NULL, &ti->session[1]); 27 | assert_int_equal(rv, CKR_OK); 28 | 29 | ti->slot = slots[0]; 30 | 31 | user_login(ti->session[0]); 32 | 33 | CK_OBJECT_CLASS key_class = CKO_PRIVATE_KEY; 34 | CK_KEY_TYPE key_type = CKK_RSA; 35 | CK_ATTRIBUTE tmpl[] = { 36 | { CKA_CLASS, &key_class, sizeof(key_class) }, 37 | { CKA_KEY_TYPE, &key_type, sizeof(key_type) }, 38 | }; 39 | 40 | rv = C_FindObjectsInit(ti->session[0], tmpl, ARRAY_LEN(tmpl)); 41 | assert_int_equal(rv, CKR_OK); 42 | 43 | count = 1; 44 | rv = C_FindObjects(ti->session[0], &ti->key, count, &count); 45 | assert_int_equal(rv, CKR_OK); 46 | assert_int_equal(count, 1); 47 | 48 | rv = C_FindObjectsFinal(ti->session[0]); 49 | assert_int_equal(rv, CKR_OK); 50 | 51 | return ti; 52 | } 53 | 54 | static int test_setup(void **state) { 55 | 56 | /* get the slots */ 57 | test_info *ti = test_info_new(); 58 | 59 | *state = ti; 60 | 61 | return 0; 62 | } 63 | 64 | static int test_teardown(void **state) { 65 | 66 | test_info *ti = test_info_from_state(state); 67 | 68 | CK_RV rv = C_CloseAllSessions(ti->slot); 69 | assert_int_equal(rv, CKR_OK); 70 | 71 | free(ti); 72 | 73 | return 0; 74 | } 75 | 76 | static void test_session_operation_state(void **state) { 77 | 78 | test_info *ti = test_info_from_state(state); 79 | 80 | CK_MECHANISM dmech = { 81 | .mechanism = CKM_SHA256, 82 | .pParameter = NULL, 83 | .ulParameterLen = 0 84 | }; 85 | 86 | CK_MECHANISM smech = { 87 | .mechanism = CKM_SHA256_RSA_PKCS, 88 | .pParameter = NULL, 89 | .ulParameterLen = 0 90 | }; 91 | 92 | CK_BYTE iv[16] = {0}; 93 | 94 | CK_MECHANISM emech = { 95 | .mechanism = CKM_AES_CBC, 96 | .pParameter = &iv, 97 | .ulParameterLen = sizeof(iv) 98 | }; 99 | 100 | 101 | CK_RV rv = C_DigestInit(ti->session[0], &dmech); 102 | assert_int_equal(rv, CKR_OK); 103 | 104 | rv = C_DigestInit(ti->session[0], &dmech); 105 | assert_int_equal(rv, CKR_OPERATION_ACTIVE); 106 | 107 | rv = C_SignInit(ti->session[0], &smech, ti->key); 108 | assert_int_equal(rv, CKR_OPERATION_ACTIVE); 109 | 110 | rv = C_SignInit(ti->session[1], &smech, ti->key); 111 | assert_int_equal(rv, CKR_OK); 112 | 113 | rv = C_DigestInit(ti->session[1], &dmech); 114 | assert_int_equal(rv, CKR_OPERATION_ACTIVE); 115 | 116 | rv = C_EncryptInit(ti->session[1], &emech, ti->key); 117 | assert_int_equal(rv, CKR_OPERATION_ACTIVE); 118 | } 119 | 120 | static void test_session_exhastion(void **state) { 121 | UNUSED(state); 122 | 123 | CK_SLOT_ID slots[6]; 124 | CK_ULONG count = ARRAY_LEN(slots); 125 | CK_RV rv = C_GetSlotList(true, slots, &count); 126 | assert_int_equal(rv, CKR_OK); 127 | 128 | CK_SESSION_HANDLE session; 129 | 130 | while ((rv = C_OpenSession(slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION, 131 | NULL_PTR, NULL_PTR, &session)) != CKR_SESSION_COUNT) { 132 | assert_int_equal(rv, CKR_OK); 133 | } 134 | 135 | rv = C_CloseAllSessions(slots[0]); 136 | assert_int_equal(rv, CKR_OK); 137 | } 138 | 139 | int main() { 140 | 141 | const struct CMUnitTest tests[] = { 142 | cmocka_unit_test_setup_teardown(test_session_operation_state, 143 | test_setup, test_teardown), 144 | /* this must go last to get C_Finalize from group_teardown called */ 145 | cmocka_unit_test(test_session_exhastion), 146 | }; 147 | 148 | return cmocka_run_group_tests(tests, group_setup, group_teardown); 149 | } 150 | -------------------------------------------------------------------------------- /test/integration/pkcs11-dbup.sh.nosetup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | 4 | set -eo pipefail 5 | 6 | if [ -z "$T" ]; then 7 | export T="$(cd "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)" 8 | fi 9 | 10 | source "$T/test/integration/scripts/helpers.sh" 11 | 12 | tempdir=$(mktemp -d) 13 | 14 | function cleanup() { 15 | rm -rf "$tempdir" 16 | } 17 | trap cleanup EXIT 18 | 19 | onerror() { 20 | echo "$BASH_COMMAND on line ${BASH_LINENO[0]} failed: $?" 21 | exit 1 22 | } 23 | trap onerror ERR 24 | 25 | # 26 | # Before we setup and possibly LD_PRELOAD the asan library, 27 | # we need to download and build v1.0 and test HEAD (current build) 28 | # against it in the tempdir. 29 | # 30 | pushd "$tempdir" 31 | 32 | oldver=1.0.3 33 | if ! wget "$PACKAGE_URL/releases/download/$oldver/tpm2-pkcs11-$oldver.tar.gz"; then 34 | echo "Could not download old version tpm2-pkcs11-$oldver.tar.gz" 35 | exit 77 36 | fi 37 | if ! sha256sum "tpm2-pkcs11-$oldver.tar.gz" | grep -q ^6542049c0cc217b4372da52ea207fcb22e15afb2e76b9dc2f3d126b3147780c7; then 38 | echo "Integrity check of tpm2-pkcs11-$oldver.tar.gz failed" 39 | exit 99 40 | fi 41 | tar xzf "tpm2-pkcs11-$oldver.tar.gz" 42 | 43 | pushd "tpm2-pkcs11-$oldver" 44 | ./configure --enable-debug --disable-hardening 45 | make -j$(nproc) 46 | popd 47 | popd 48 | 49 | echo "PWD: $(pwd)" 50 | 51 | # modpath will be to the HEAD version library 52 | if [ -z "$modpath" ]; then 53 | modpath="$(pwd)/src/.libs/libtpm2_pkcs11.so" 54 | fi 55 | 56 | echo "modpath=$modpath" 57 | 58 | setup_asan 59 | 60 | pkcs11_tool() { 61 | pkcs11-tool --module "$modpath" "$@" 62 | return $? 63 | } 64 | 65 | export TPM2_PKCS11_STORE="$tempdir" 66 | 67 | echo "TPM2_PKCS11_STORE=$TPM2_PKCS11_STORE" 68 | 69 | # 70 | # Since OLD is on 1.0, it won't automagically populate a store. 71 | # So we need to use the 1.0 tpm2_ptool 72 | # XXX should we prepend the current? 73 | # 74 | PYTHONPATH=$tempdir/tpm2-pkcs11-$oldver/tools 75 | echo $PYTHONPATH 76 | 77 | tpm2_ptool init 78 | tpm2_ptool addtoken --pid=1 --sopin=mysopin --userpin=myuserpin --label=label 79 | 80 | # at this point we can verify the db schema version 81 | echo "Checking schema version as 1" 82 | v=$(sqlite3 "$TPM2_PKCS11_STORE/tpm2_pkcs11.sqlite3" 'select schema_version from schema;') 83 | echo "Got schema version as $v" 84 | test 1 -eq $v 85 | 86 | # do an upgrade 87 | echo "Generating RSA key pair" 88 | pkcs11_tool --slot=1 --label="myrsakey" --login --pin=myuserpin --keypairgen 89 | echo "RSA Key pair generated" 90 | 91 | echo "Checking schema version as > 1" 92 | v=$(sqlite3 "$TPM2_PKCS11_STORE/tpm2_pkcs11.sqlite3" 'select schema_version from schema;') 93 | echo "Got schema version as $v" 94 | test $v -ge 1 95 | 96 | echo "testdata">${tempdir}/data 97 | 98 | echo "Using key to ensure it still works" 99 | pkcs11_tool -v --sign --login --slot-index=0 --label="myrsakey" --pin myuserpin \ 100 | --input-file ${tempdir}/data --output-file ${tempdir}/sig \ 101 | --mechanism SHA256-RSA-PKCS 102 | echo "Successfully used key post schema upgrade" 103 | 104 | exit 0 105 | -------------------------------------------------------------------------------- /test/integration/pkcs11-javarunner.sh.java: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | 4 | set -e 5 | 6 | if [ "$ASAN_ENABLED" = "true" ]; then 7 | # Skip this test when ASAN is enabled 8 | exit 77 9 | fi 10 | 11 | export CLASSPATH="$CLASSPATH:$TEST_JAVA_ROOT" 12 | 13 | echo "CLASSPATH=$CLASSPATH" 14 | 15 | #dont use -cp here, it causes env CLASSPATH not to be used 16 | java PKCS11JavaTests 17 | 18 | exit 0 19 | -------------------------------------------------------------------------------- /test/integration/pkcs11-tool-init-fapi.sh.fapi: -------------------------------------------------------------------------------- 1 | pkcs11-tool-init.sh.nosetup -------------------------------------------------------------------------------- /test/integration/pkcs11-tool-init.sh.nosetup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | 4 | set -x 5 | 6 | if [ -z "$T" ]; then 7 | export T="$(cd "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)" 8 | fi 9 | 10 | source "$T/test/integration/scripts/helpers.sh" 11 | 12 | tempdir=$(mktemp -d) 13 | 14 | function cleanup() { 15 | rm -rf "$tempdir" 16 | } 17 | trap cleanup EXIT 18 | 19 | onerror() { 20 | echo "$BASH_COMMAND on line ${BASH_LINENO[0]} failed: $?" 21 | exit 1 22 | } 23 | trap onerror ERR 24 | 25 | setup_asan 26 | 27 | if [ -z "$modpath" ]; then 28 | modpath="$PWD/src/.libs/libtpm2_pkcs11.so" 29 | fi 30 | 31 | echo "modpath=$modpath" 32 | 33 | pkcs11_tool() { 34 | pkcs11-tool --module "$modpath" "$@" 35 | return $? 36 | } 37 | 38 | export TPM2_PKCS11_STORE="$tempdir" 39 | 40 | echo "TPM2_PKCS11_STORE=$TPM2_PKCS11_STORE" 41 | 42 | echo "testdata">${tempdir}/data 43 | 44 | echo "Should have uninitialized token" 45 | pkcs11_tool -T | grep -q uninitialized 46 | echo "Found uninitialized token" 47 | 48 | pkcs11_tool -I 49 | pkcs11_tool -T 50 | 51 | # Their is no SRK so it should attempt to make an SRK, so lets test it with an owner 52 | # hierarchy password set to make sure that works. 53 | tpm2_changeauth -cowner mynewpass 54 | export TPM2_PKCS11_OWNER_AUTH=mynewpass 55 | 56 | echo "Initializing token" 57 | pkcs11_tool --slot-index=0 --init-token --label=mynewtoken --so-pin=mynewsopin 58 | echo "Token initialized" 59 | 60 | pkcs11_tool -T 61 | 62 | echo "Initializing user pin" 63 | pkcs11_tool --slot-index=0 --login --login-type="so" --init-pin --so-pin=mynewsopin --pin=mynewuserpin 64 | echo "Userpin initialized" 65 | 66 | echo "Generating RSA key pair" 67 | pkcs11_tool --slot-index=0 --label="myrsakey" --login --pin=mynewuserpin --keypairgen 68 | echo "RSA Key pair generated" 69 | 70 | echo "Testing RSA signature" 71 | pkcs11_tool -v --list-objects --login --pin mynewuserpin 72 | 73 | pkcs11_tool -v --sign --login --slot-index=0 --label="myrsakey" --pin mynewuserpin \ 74 | --input-file ${tempdir}/data --output-file ${tempdir}/sig \ 75 | --mechanism SHA256-RSA-PKCS 76 | 77 | pkcs11_tool -v --read-object --slot-index=0 --label="myrsakey" \ 78 | --type pubkey --output-file ${tempdir}/pubkey.der \ 79 | || exit 77 80 | #This fails on old pkcs11-tool versions, thus exit-skip here 81 | 82 | openssl dgst -verify ${tempdir}/pubkey.der -keyform DER -signature ${tempdir}/sig -sha256 \ 83 | -sigopt rsa_padding_mode:pkcs1 \ 84 | ${tempdir}/data 85 | echo "RSA signature tested" 86 | 87 | echo "Change PIN test" 88 | pkcs11_tool --change-pin --slot-index=0 --pin=mynewuserpin --login --new-pin=temppin 89 | pkcs11_tool --change-pin --slot-index=0 --pin=temppin --login --new-pin=mynewuserpin 90 | echo "PIN change tested" 91 | 92 | # 93 | # Regression test for https://github.com/tpm2-software/tpm2-pkcs11/issues/399 94 | # Delete Private Key then Public Key. 95 | pkcs11_tool --delete-object --slot-index=0 --label="myrsakey" --pin=mynewuserpin --login --type=privkey 96 | pkcs11_tool --list-objects --slot-index=0 97 | 98 | pkcs11_tool --delete-object --slot-index=0 --label="myrsakey" --pin=mynewuserpin --login --type=pubkey 99 | pkcs11_tool --list-objects --slot-index=0 100 | 101 | # 102 | # Test creating data objects 103 | # 104 | echo "hello world" > objdata 105 | pkcs11_tool --slot-index=0 --login --pin=mynewuserpin --write-object objdata --type data --label dataobj1 --private 106 | 107 | # whitebox test to make sure secret is not in store 108 | if [ "$TPM2_PKCS11_BACKEND" != "fapi" ]; then 109 | sqlite3 "$TPM2_PKCS11_STORE/tpm2_pkcs11.sqlite3" 'select attrs from tobjects;' | grep -qiv "$(cat objdata)" 110 | # and check for the hex encoded version too 111 | sqlite3 "$TPM2_PKCS11_STORE/tpm2_pkcs11.sqlite3" 'select attrs from tobjects;' | grep -qiv "$(xxd -p objdata)" 112 | fi 113 | 114 | pkcs11_tool --slot-index=0 --login --pin=mynewuserpin --read-object --type data --label dataobj1 -o objdata2 115 | cmp objdata objdata2 116 | 117 | exit 0 118 | -------------------------------------------------------------------------------- /test/integration/python-pkcs11.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | 4 | set -exo pipefail 5 | 6 | if [ -z "$T" ]; then 7 | export T="$(cd "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)" 8 | fi 9 | 10 | source "$T/test/integration/scripts/helpers.sh" 11 | 12 | setup_asan 13 | 14 | "${PYTHON_INTERPRETER:-python3}" - <<'_SCRIPT_' 15 | import os 16 | import unittest 17 | 18 | import pkcs11 19 | 20 | class TestPKCS11(unittest.TestCase): 21 | @classmethod 22 | def setUpClass(cls): 23 | path = os.getenv('TPM2_PKCS11_MODULE', os.path.join(os.getcwd(), 'src/.libs/libtpm2_pkcs11.so')) 24 | lib = pkcs11.lib(path) 25 | cls._token = lib.get_token(token_label='label') 26 | 27 | def test_CKM_PKCS11(self): 28 | with self._token.open(rw=False, user_pin='myuserpin') as session: 29 | 30 | public = session.get_key(label='rsa0',object_class=pkcs11.constants.ObjectClass.PUBLIC_KEY) 31 | private = session.get_key(label='rsa0',object_class=pkcs11.constants.ObjectClass.PRIVATE_KEY) 32 | 33 | original = plaintext = b'1234567890123456' 34 | ciphertext = public.encrypt(plaintext, mechanism=pkcs11.mechanisms.Mechanism.RSA_PKCS) 35 | self.assertNotEqual(plaintext, ciphertext) 36 | 37 | plaintext = 'notdecrypted' 38 | plaintext = private.decrypt(ciphertext, mechanism=pkcs11.mechanisms.Mechanism.RSA_PKCS) 39 | # strip padding 40 | p2 = plaintext[-len(original):] 41 | self.assertEqual(p2, original) 42 | 43 | if __name__ == '__main__': 44 | unittest.main() 45 | _SCRIPT_ 46 | 47 | exit $? 48 | -------------------------------------------------------------------------------- /test/integration/scripts/helpers.sh: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-2-Clause 2 | #!/usr/bin/env bash 3 | 4 | setup_asan() { 5 | if [ "$ASAN_ENABLED" != "true" ]; then 6 | return 0 7 | fi 8 | 9 | # To get line numbers set up the asan symbolizer 10 | clang_version=`$CC --version | head -n 1 | cut -d\ -f 3-3 | cut -d\. -f 1-3 | cut -d- -f 1-1` 11 | # Sometimes the version string has an Ubuntu on the front of it and the field 12 | # location changes 13 | if [ $clang_version == "version" ]; then 14 | clang_version=`$CC --version | head -n 1 | cut -d\ -f 4-4 | cut -d\. -f 1-3` 15 | fi 16 | 17 | # sometimes thier is an rc version 18 | if grep -qi '\-+rc' <<< "$clang_version"; then 19 | clang_version=$(echo "$clang_version" | cut -d'-' -f1-1) 20 | fi 21 | 22 | echo "Detected clang version: $clang_version" 23 | minor_maj=`echo "$clang_version" | cut -d\. -f 1-2` 24 | maj=`echo "$clang_version" | cut -d\. -f 1-1` 25 | 26 | p="/usr/lib/llvm-$minor_maj/lib/clang/$clang_version/lib/linux/libclang_rt.asan-$(arch).so" 27 | echo "Looking for libasan to LD_PRELOAD at: $p" 28 | if [ ! -f "$p" ]; then 29 | p="/usr/lib/llvm-$maj/lib/clang/$clang_version/lib/linux/libclang_rt.asan-$(arch).so" 30 | fi 31 | if [ ! -f "$p" ]; then 32 | p="/usr/lib64/clang/$clang_version/lib/linux/libclang_rt.asan-$(arch).so" 33 | fi 34 | if [ ! -f "$p" ]; then 35 | p="/usr/lib64/clang/$maj/lib/linux/libclang_rt.asan-$(arch).so" 36 | fi 37 | 38 | if [ ! -f "$p" ]; then 39 | echo "Couldn't find libasan.so" 40 | return -1 41 | fi 42 | echo "Found libasan at: $p" 43 | 44 | export LD_PRELOAD="$p" 45 | echo "export LD_PRELOAD=\"$LD_PRELOAD\"" 46 | export ASAN_OPTIONS=detect_leaks=0 47 | echo "turning off asan detection for running commands..." 48 | 49 | return 0 50 | } 51 | 52 | clear_asan() { 53 | unset LD_PRELOAD 54 | unset ASAN_OPTIONS 55 | } 56 | 57 | setup_ca() { 58 | CA_DIR=`mktemp -d -t tpm2tmpca.XXXXXX` 59 | 60 | export CA_DIR 61 | export CA_PEM="$CA_DIR/ca.pem" 62 | export CA_KEY="$CA_DIR/ca.key" 63 | 64 | # Generate CA CERT and CA KEY 65 | openssl req \ 66 | -x509 \ 67 | -nodes \ 68 | -days 3650 \ 69 | -newkey rsa:2048 \ 70 | -keyout "$CA_KEY" \ 71 | -out "$CA_PEM" \ 72 | -subj "/C=US/ST=Radius/L=Somewhere/O=Example Inc./CN=example.com" 73 | 74 | # make the DB 75 | touch "$CA_DIR"/index.txt 76 | touch "$CA_DIR"/index.txt.attr 77 | echo "01" >> "$CA_DIR"/serial 78 | } 79 | 80 | cleanup_ca() 81 | { 82 | test -n "$CA_DIR" || return 0 83 | rm -rf "$CA_DIR" 84 | } 85 | 86 | check_openssl_version() 87 | { 88 | # do this in an if statement so it can fail and not cause 89 | # set -e (execfail) to exit the script 90 | if pkg-config --exists 'libcrypto < 3'; then 91 | OSSL3_DETECTED=0 92 | else 93 | OSSL3_DETECTED=1 94 | fi 95 | } 96 | 97 | -------------------------------------------------------------------------------- /test/integration/test.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #ifndef TEST_INTEGRATION_TEST_H_ 4 | #define TEST_INTEGRATION_TEST_H_ 5 | 6 | #include "config.h" 7 | 8 | /* Set up ALL the headers needed so tests can just use #include "test.h" */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | #include "ssl_util.h" 22 | #include "pkcs11.h" 23 | #include "ssl_util.h" 24 | #include "utils.h" 25 | 26 | /* 4 in db tokens + 1 uninitialized token */ 27 | #define TOKEN_COUNT (4 + 1) 28 | 29 | #define GOOD_USERPIN "myuserpin" 30 | #define GOOD_SOPIN "mysopin" 31 | 32 | #define BAD_USERPIN "myBADuserpin" 33 | #define BAD_SOPIN "myBADsopin" 34 | 35 | #define IMPORT_LABEL_USERPIN "anotheruserpin" 36 | 37 | typedef struct test_info test_info; 38 | 39 | #define ADD_ATTR_BASE(t, x) { .type = t, .ulValueLen = sizeof(x), .pValue = &x } 40 | #define ADD_ATTR_ARRAY(t, x) { .type = t, .ulValueLen = ARRAY_LEN(x), .pValue = x } 41 | #define ADD_ATTR_STR(t, x) { .type = t, .ulValueLen = sizeof(x) - 1, .pValue = x } 42 | 43 | /* 44 | * If UNIT_TESTING is defined, cmocka will hijack allocation routines to look for memory leaks. 45 | * It checks at the end of the test via fail_if_blocks_allocated, and if true will free 46 | * the blocks causing any de-allocation/teardown routines defined after the test to access 47 | * and free memory already free'd. To remedy this, define some always safe alloc routines. 48 | */ 49 | #if defined(calloc) 50 | #undef calloc 51 | #endif 52 | 53 | #if defined(free) 54 | #undef free 55 | #endif 56 | 57 | #if defined(malloc) 58 | #undef malloc 59 | #endif 60 | 61 | #if defined(realloc) 62 | #undef realloc 63 | #endif 64 | 65 | test_info *test_info_from_state(void **state); 66 | 67 | int group_setup(void **state); 68 | 69 | int group_setup_locking(void **state); 70 | 71 | int group_teardown(void **state); 72 | 73 | void logout_expects(CK_SESSION_HANDLE handle, CK_RV expected); 74 | 75 | void logout(CK_SESSION_HANDLE handle); 76 | 77 | void login_expects(CK_SESSION_HANDLE handle, CK_USER_TYPE user_type, CK_RV expected, unsigned char *pin, CK_ULONG len); 78 | 79 | void user_login_expects(CK_SESSION_HANDLE handle, CK_RV expected); 80 | 81 | void user_login_bad_pin(CK_SESSION_HANDLE handle); 82 | 83 | void user_login(CK_SESSION_HANDLE handle); 84 | 85 | void context_login(CK_SESSION_HANDLE handle); 86 | 87 | void context_login_expects(CK_SESSION_HANDLE handle, CK_RV expected); 88 | 89 | void context_login_bad_pin(CK_SESSION_HANDLE handle); 90 | 91 | void so_login_expects(CK_SESSION_HANDLE handle, CK_RV expected); 92 | 93 | void so_login(CK_SESSION_HANDLE handle); 94 | 95 | void so_login_bad_pin(CK_SESSION_HANDLE handle); 96 | 97 | void get_keypair(CK_SESSION_HANDLE session, CK_KEY_TYPE key_type, CK_OBJECT_HANDLE_PTR pub_handle, CK_OBJECT_HANDLE_PTR priv_handle); 98 | 99 | void verify_missing_pub_attrs_common(CK_SESSION_HANDLE session, CK_KEY_TYPE keytype, CK_OBJECT_HANDLE h); 100 | 101 | void verify_missing_priv_attrs_common(CK_SESSION_HANDLE session, CK_KEY_TYPE keytype, CK_OBJECT_HANDLE h, CK_BBOOL extractable); 102 | 103 | void verify_missing_pub_attrs_ecc(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE h); 104 | 105 | void verify_missing_priv_attrs_ecc(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE h); 106 | 107 | void verify_missing_pub_attrs_rsa(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE h); 108 | 109 | void verify_missing_priv_attrs_rsa(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE h); 110 | #endif /* TEST_INTEGRATION_TEST_H_ */ 111 | -------------------------------------------------------------------------------- /test/integration/tls-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | 4 | set -xo pipefail 5 | 6 | if [ -z "$T" ]; then 7 | export T="$(cd "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)" 8 | fi 9 | 10 | source "$T/test/integration/scripts/helpers.sh" 11 | 12 | EXT_FILE="$TEST_FIXTURES/xpextensions" 13 | CLIENT_CNF="$TEST_FIXTURES/client.cnf" 14 | 15 | # details on the PKCS11 URI can be found here: https://tools.ietf.org/html/rfc7512 16 | PKCS11_KEY="pkcs11:model=SW%20%20%20TPM;manufacturer=IBM;serial=0000000000000000;token=label;object=rsa0;type=private" 17 | 18 | if [ "$ASAN_ENABLED" = "true" ]; then 19 | # Skip this test when ASAN is enabled 20 | exit 77 21 | fi 22 | 23 | check_openssl_version 24 | 25 | export TPM2OPENSSL_TCTI="$TPM2TOOLS_TCTI" 26 | 27 | function cleanup() { 28 | if [ "$1" != "no-kill" ]; then 29 | pkill -P $$ || true 30 | fi 31 | cleanup_ca 32 | rm -f server.csr server.crt server.key server.pem client.csr client.crt client_tpm.pem 33 | } 34 | trap cleanup EXIT 35 | 36 | onerror() { 37 | echo "$BASH_COMMAND on line ${BASH_LINENO[0]} failed: $?" 38 | exit 1 39 | } 40 | trap onerror ERR 41 | 42 | cleanup "no-kill" 43 | 44 | # setup the CA BEFORE EXPORTING THE CA CONF for the clients 45 | setup_ca 46 | 47 | # create and sign standard file-based cert for server 48 | openssl genrsa -out server.key 2048 49 | openssl req -new -key server.key -out server.csr -subj "/C=US/ST=Radius/L=Somewhere/O=Example Inc./CN=server.example.com" 50 | openssl ca -batch -keyfile "$CA_KEY" -cert "$CA_PEM" -in server.csr -out server.crt -config "$CLIENT_CNF" 51 | openssl x509 -in server.crt -out server.pem -outform pem 52 | 53 | # create and sign PKCS#11 cert for client 54 | if [ "$OSSL3_DETECTED" -eq "0" ]; then 55 | export OPENSSL_CONF="$TEST_FIXTURES/ossl.cnf" 56 | openssl req -new -engine pkcs11 -keyform engine -key "$PKCS11_KEY" -out client.csr -subj "/C=US/ST=Radius/L=Somewhere/O=Example Inc./CN=testing/emailAddress=testing@123.com" 57 | else 58 | pushd $TPM2_PKCS11_STORE 59 | yaml_rsa0=$(tpm2_ptool export --label=label --userpin=myuserpin --key-label=rsa0 --path=$TPM2_PKCS11_STORE) 60 | popd 61 | 62 | auth_rsa0=$(echo "$yaml_rsa0" | grep "object-auth" | cut -d' ' -f2-) 63 | 64 | TPM2OPENSSL_PARENT_AUTH="mypobjpin" openssl req -new -provider tpm2 -provider base \ 65 | -key "$TPM2_PKCS11_STORE/rsa0.pem" -passin "pass:$auth_rsa0" \ 66 | -subj "/C=US/ST=Radius/L=Somewhere/O=Example Inc./CN=testing/emailAddress=testing@123.com" \ 67 | -out client.csr 68 | fi 69 | 70 | openssl ca -batch -keyfile "$CA_KEY" -cert "$CA_PEM" -in client.csr -out client.crt -extensions xpclient_ext -extfile "$EXT_FILE" -config "$CLIENT_CNF" 71 | openssl x509 -in client.crt -out client_tpm.pem -outform pem 72 | 73 | # OpenSSL version 1.0.2g ends up in a state where it tries to read from stdin instead of the ssl connection. 74 | # Feeding it one byte as stdin avoids this condition which is described in more detail here: 75 | # https://github.com/tpm2-software/tpm2-pkcs11/pull/366 76 | openssl s_server -debug -CAfile "$CA_PEM" -cert server.pem -key server.key -Verify 1 <<< '1' & 77 | sleep 1 78 | 79 | # default connects to 127.0.0.1:443 80 | if [ "$OSSL3_DETECTED" -eq "0" ]; then 81 | openssl s_client -engine pkcs11 -keyform engine -key "$PKCS11_KEY" -CAfile "$CA_PEM" -cert client_tpm.pem <<< 'Q' 82 | else 83 | TPM2OPENSSL_PARENT_AUTH="mypobjpin" openssl s_client -provider tpm2 -provider default \ 84 | -key "$TPM2_PKCS11_STORE/rsa0.pem" -pass "pass:$auth_rsa0" -ignore_unexpected_eof \ 85 | -CAfile "$CA_PEM" -cert client_tpm.pem <<< 'Q' 86 | fi 87 | exit 0 88 | -------------------------------------------------------------------------------- /test/unit/test_attr.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "attrs.h" 15 | 16 | static void test_config_parser_empty_seq(void **state) { 17 | (void) state; 18 | 19 | attr_list *attrs = attr_list_new(); 20 | assert_non_null(attrs); 21 | 22 | bool r = attr_list_add_int(attrs, CKA_CLASS, CKO_CERTIFICATE); 23 | assert_true(r); 24 | 25 | r = attr_list_add_buf(attrs, CKA_ID, (CK_BYTE_PTR)"2132333435", 10); 26 | assert_true(r); 27 | 28 | r = attr_list_add_bool(attrs, CKA_DECRYPT, CK_TRUE); 29 | assert_true(r); 30 | 31 | /* test class */ 32 | CK_ATTRIBUTE_PTR a = attr_get_attribute_by_type(attrs, CKA_CLASS); 33 | assert_non_null(a); 34 | CK_OBJECT_CLASS got_class = CKO_DATA; 35 | CK_RV rv = attr_CK_OBJECT_CLASS(a, &got_class); 36 | assert_int_equal(rv, CKR_OK); 37 | assert_int_equal(got_class, CKO_CERTIFICATE); 38 | 39 | /* test id */ 40 | a = attr_get_attribute_by_type(attrs, CKA_ID); 41 | assert_non_null(a); 42 | assert_int_equal(a->ulValueLen, 10); 43 | assert_memory_equal(a->pValue, "2132333435", 10); 44 | 45 | /* test decrypt */ 46 | a = attr_get_attribute_by_type(attrs, CKA_DECRYPT); 47 | assert_non_null(a); 48 | CK_BBOOL got_bool = CK_FALSE; 49 | rv = attr_CK_BBOOL(a, &got_bool); 50 | assert_int_equal(rv, CKR_OK); 51 | assert_int_equal(got_bool, CK_TRUE); 52 | 53 | /* test shouldn't be there */ 54 | a = attr_get_attribute_by_type(attrs, CKA_SIGN); 55 | assert_null(a); 56 | 57 | attr_list_free(attrs); 58 | } 59 | 60 | int main(int argc, char* argv[]) { 61 | (void) argc; 62 | (void) argv; 63 | 64 | const struct CMUnitTest tests[] = { 65 | cmocka_unit_test(test_config_parser_empty_seq), 66 | }; 67 | 68 | return cmocka_run_group_tests(tests, NULL, NULL); 69 | } 70 | -------------------------------------------------------------------------------- /test/unit/test_log.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include "log.h" 16 | #include "utils.h" 17 | 18 | void test_log_levels(void **state) { 19 | (void) state; 20 | 21 | char *levels[] = {"abc", "-1", "0", "1", "2", "3", "4"}; 22 | for (int i = 0; i < 7; i++) { 23 | setenv("TPM2_PKCS11_LOG_LEVEL", levels[i], 1); 24 | LOGV("Test %i", i); 25 | LOGW("Test %i", i); 26 | LOGE("Test %i", i); 27 | } 28 | } 29 | 30 | int main(int argc, char* argv[]) { 31 | (void) argc; 32 | (void) argv; 33 | 34 | const struct CMUnitTest tests[] = { 35 | cmocka_unit_test(test_log_levels), 36 | }; 37 | 38 | return cmocka_run_group_tests(tests, NULL, NULL); 39 | } 40 | -------------------------------------------------------------------------------- /test/unit/test_utils.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: BSD-2-Clause */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "utils.h" 15 | 16 | static void test_parse_lib_version(void **state) { 17 | (void) state; 18 | 19 | CK_BYTE major = 0xFF; 20 | CK_BYTE minor = 0xFF; 21 | parse_lib_version("1", &major, &minor); 22 | assert_int_equal(major, 1); 23 | assert_int_equal(minor, 0); 24 | 25 | major = 0xFF; 26 | minor = 0xFF; 27 | parse_lib_version("5.2", &major, &minor); 28 | assert_int_equal(major, 5); 29 | assert_int_equal(minor, 2); 30 | 31 | major = 0xFF; 32 | minor = 0xFF; 33 | parse_lib_version("9.8.7", &major, &minor); 34 | assert_int_equal(major, 9); 35 | assert_int_equal(minor, 8); 36 | 37 | major = 0xFF; 38 | minor = 0xFF; 39 | parse_lib_version("1.6.0-42-gb462a23778ea-dirty", &major, &minor); 40 | assert_int_equal(major, 0); 41 | assert_int_equal(minor, 0); 42 | 43 | major = 0xFF; 44 | minor = 0xFF; 45 | parse_lib_version("1.6.0-", &major, &minor); 46 | assert_int_equal(major, 0); 47 | assert_int_equal(minor, 0); 48 | 49 | major = 0xFF; 50 | minor = 0xFF; 51 | parse_lib_version("", &major, &minor); 52 | assert_int_equal(major, 0); 53 | assert_int_equal(minor, 0); 54 | 55 | major = 0xFF; 56 | minor = 0xFF; 57 | parse_lib_version(NULL, &major, &minor); 58 | assert_int_equal(major, 0); 59 | assert_int_equal(minor, 0); 60 | } 61 | 62 | int main(int argc, char* argv[]) { 63 | (void) argc; 64 | (void) argv; 65 | 66 | const struct CMUnitTest tests[] = { 67 | cmocka_unit_test(test_parse_lib_version), 68 | }; 69 | 70 | return cmocka_run_group_tests(tests, NULL, NULL); 71 | } 72 | -------------------------------------------------------------------------------- /tools/.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-2-Clause 2 | *__pycache__/ 3 | *.swp 4 | *.pyc 5 | *.egg-info/ 6 | -------------------------------------------------------------------------------- /tools/setup.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-2-Clause 2 | from setuptools import setup 3 | from textwrap import dedent as DD 4 | 5 | long_description = DD(''' 6 | This tool is used to configure and manipulate stores for the tpm2-pkcs11 7 | cryptographic library. 8 | ''') 9 | 10 | setup( 11 | name='tpm2-pkcs11-tools', 12 | python_requires='>=3.7', 13 | long_description=long_description, 14 | long_description_content_type='text/markdown', 15 | version='1.33.7', 16 | description='Command line tools for the TPM2.0 PKCS11 module', 17 | url='https://github.com/tpm2-software/tpm2-pkcs11', 18 | license='BSD2', 19 | keywords=['', ], 20 | classifiers=[ 21 | 'Development Status :: 2 - Pre-Alpha', 22 | 'Intended Audience :: Developers', 23 | 'Intended Audience :: System Administrators', 24 | 'License :: OSI Approved :: BSD License', 25 | 'Environment :: Console', 26 | 'Natural Language :: English', 27 | 'Operating System :: OS Independent', 28 | 'Programming Language :: Python', 29 | ], 30 | packages=['tpm2_pkcs11'], 31 | 32 | # Dependencies got here aka install_requires=['tensorflow'] 33 | install_requires=[ 34 | 'bcrypt', 35 | 'cryptography>=3.0', 36 | 'pyyaml', 37 | 'pyasn1', 38 | 'pyasn1_modules', 39 | 'tpm2_pytss' 40 | ], 41 | entry_points={ 42 | 'console_scripts': ['tpm2_ptool = tpm2_pkcs11.tpm2_ptool:main'], 43 | }, ) 44 | -------------------------------------------------------------------------------- /tools/tpm2_pkcs11/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-2-Clause 2 | 3 | import sys 4 | 5 | # Requires python 3.7 or greater 6 | if (sys.version_info[0], sys.version_info[1]) < (3, 7): 7 | sys.exit("Python 3.7 or a more recent version is required.") -------------------------------------------------------------------------------- /tools/tpm2_pkcs11/command.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-2-Clause 2 | import argparse 3 | import os 4 | import textwrap 5 | 6 | class commandlet(object): 7 | '''Decorator class for commandlet. You can add commandlets to the tool with this decorator.''' 8 | 9 | @staticmethod 10 | def get_default_store_path(): 11 | 12 | # always use the env variable no matter what 13 | if "TPM2_PKCS11_STORE" in os.environ: 14 | store = os.environ.get("TPM2_PKCS11_STORE") 15 | try: 16 | os.mkdir(store, 0o770) 17 | except FileExistsError: 18 | return store 19 | except Exception: 20 | # Keep trying 21 | pass 22 | # Exists, use it 23 | return store 24 | 25 | # is there a system store and can I access it? 26 | store = "/etc/tpm2_pkcs11" 27 | if os.path.exists(store) and os.access(store, os.W_OK): 28 | return store 29 | 30 | # look for a store in home 31 | if "HOME" in os.environ: 32 | if "XDG_DATA_HOME" in os.environ: 33 | data_dir = os.environ["XDG_DATA_HOME"] 34 | else: 35 | data_dir = os.path.join(os.environ["HOME"], ".local/share") 36 | 37 | stores = [ 38 | os.path.join(data_dir, "tpm2-pkcs11"), 39 | os.path.join(os.environ["HOME"], ".tpm2_pkcs11"), 40 | ] 41 | 42 | # Try to find existing store 43 | for store in stores: 44 | if os.path.exists(store): 45 | return store 46 | 47 | # If neither path exists, try to create one 48 | for store in stores: 49 | try: 50 | os.mkdir(store, 0o770) 51 | except FileExistsError: 52 | return store 53 | except Exception: 54 | continue 55 | # Exists, use it 56 | return store 57 | 58 | # nothing else available, use cwd 59 | return os.getcwd() 60 | 61 | _commandlets = {} 62 | 63 | def __init__(self, cmd): 64 | self._cmd = cmd 65 | 66 | if cmd in commandlet._commandlets: 67 | raise Exception('Duplicate command name' + cmd) 68 | 69 | commandlet._commandlets[cmd] = None 70 | 71 | def __call__(self, cls): 72 | commandlet._commandlets[self._cmd] = cls() 73 | return cls 74 | 75 | @staticmethod 76 | def get(): 77 | '''Retrieves the list of registered commandlets.''' 78 | return commandlet._commandlets 79 | 80 | @staticmethod 81 | def init(description): 82 | 83 | opt_parser = argparse.ArgumentParser(description=description) 84 | 85 | subparser = opt_parser.add_subparsers(help='commands') 86 | 87 | commandlets = commandlet.get() 88 | 89 | # for each commandlet, instantiate and set up their options 90 | for n, c in commandlets.items(): 91 | p = subparser.add_parser(n, help=c.__doc__) 92 | p.set_defaults(which=n) 93 | # Instantiate 94 | 95 | opt_gen = getattr(c, 'generate_options', None) 96 | if callable(opt_gen): 97 | # get group help 98 | g = p.add_argument_group(n + ' options') 99 | # get args 100 | c.generate_options(g) 101 | g.add_argument( 102 | '--path', 103 | type=os.path.expanduser, 104 | help=textwrap.dedent(''' 105 | The location of the store directory. If specified, the directory MUST exist. 106 | If not specified performs a search by looking at environment variable 107 | TPM2_PKCS11_STORE and if not set then /etc/tpm2_pkcs11 and if not found or 108 | no write access, then $HOME/.tpm2_pkcs11 and if not found or cannot be created, 109 | then defaults to using the current working directory. 110 | '''), 111 | default=commandlet.get_default_store_path()) 112 | 113 | args = opt_parser.parse_args() 114 | 115 | d = vars(args) 116 | if 'which' in d: 117 | commandlet.get()[d['which']](d) 118 | else: 119 | opt_parser.print_usage() 120 | 121 | 122 | class Command(object): 123 | '''Baseclass for a commandlet. Commandlets shall implement this interface.''' 124 | 125 | def generate_options(self, group_parser): 126 | '''Adds it's options to the group parser. The parser passed in is a result from 127 | calling add_argument_group(ArgumentGroup): https://docs.python.org/2/library/argparse.html 128 | Args: 129 | group_parser(): The parser to add options too. 130 | ''' 131 | raise NotImplementedError('Implement: generate_options') 132 | 133 | def __call__(self, args): 134 | '''Called when the user selects your commandlet and passed the dictionary of arguments. 135 | Arguments: 136 | args ({str: arg}: The dictionary version of the attrs of the parser. 137 | The args value is obtained by: 138 | args = opt_parser.parse_args() 139 | args = vars(args) 140 | So to access args just do args['name'] 141 | ''' 142 | raise NotImplementedError('Implement: __call__') 143 | -------------------------------------------------------------------------------- /tools/tpm2_pkcs11/pkcs11t.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-2-Clause 2 | # These CK* values come from the PKCS#11 spec 3 | CKO_CERTIFICATE = 0x1 4 | CKO_PUBLIC_KEY = 0x2 5 | CKO_PRIVATE_KEY = 0x3 6 | CKO_SECRET_KEY = 0x4 7 | 8 | CKK_RSA = 0x0 9 | CKK_EC = 0x3 10 | CKK_GENERIC_SECRET = 0x10 11 | CKK_AES = 0x1f 12 | 13 | CKK_SHA_1_HMAC = 0x28 14 | CKK_SHA256_HMAC=0x2b 15 | CKK_SHA384_HMAC=0x2c 16 | CKK_SHA512_HMAC=0x2d 17 | 18 | CKM_RSA_PKCS_KEY_PAIR_GEN = 0x0 19 | CKM_RSA_PKCS = 0x1 20 | CKM_RSA_X_509 = 0x3 21 | CKM_SHA1_RSA_PKCS = 0x6 22 | CKM_RSA_PKCS_OAEP = 0x9 23 | CKM_RSA_PKCS_PSS = 0xD 24 | CKM_SHA1_RSA_PKCS_PSS = 0xE 25 | CKM_SHA256_RSA_PKCS = 0x40 26 | CKM_SHA384_RSA_PKCS = 0x41 27 | CKM_SHA512_RSA_PKCS = 0x42 28 | CKM_SHA256_RSA_PKCS_PSS = 0x43 29 | CKM_SHA384_RSA_PKCS_PSS = 0x44 30 | CKM_SHA512_RSA_PKCS_PSS = 0x45 31 | CKM_GENERIC_SECRET_KEY_GEN = 0x350 32 | CKM_AES_CBC = 0x1082 33 | CKM_AES_CBC_PAD = 0x1085 34 | CKM_EC_KEY_PAIR_GEN = 0x1040 35 | CKM_ECDSA = 0x1041 36 | CKM_ECDSA_SHA1 = 0x1042 37 | CKM_ECDSA_SHA256 = 0x1044 38 | CKM_ECDSA_SHA384 = 0x1045 39 | CKM_ECDSA_SHA512 = 0x1046 40 | CKM_AES_KEY_GEN = 0x1080 41 | CKM_AES_ECB = 0x1081 42 | CKM_AES_CTR = 0x1086 43 | CKM_SHA_1 = 0x220 44 | CKG_MGF1_SHA1 = 0x1 45 | CKM_AES_OFB = 0x2104 46 | CKM_AES_CFB128 = 0x2107 47 | CKM_SHA_1_HMAC = 0x221 48 | CKM_SHA256_HMAC = 0x251 49 | CKM_SHA384_HMAC = 0x261 50 | CKM_SHA512_HMAC = 0x271 51 | 52 | CKG_MGF1_SHA256 = 0x2 53 | 54 | CKA_CLASS = 0x0 55 | CKA_TOKEN = 0x1 56 | CKA_PRIVATE = 0x2 57 | CKA_LABEL = 0x3 58 | CKA_VALUE = 0x11 59 | CKA_CERTIFICATE_TYPE = 0x80 60 | CKA_ISSUER = 0x81 61 | CKA_SERIAL_NUMBER = 0x82 62 | CKA_TRUSTED = 0x86 63 | CKA_CERTIFICATE_CATEGORY = 0x87 64 | CKA_JAVA_MIDP_SECURITY_DOMAIN = 0x88 65 | CKA_URL = 0x89 66 | CKA_CHECK_VALUE = 0x90 67 | CKA_HASH_OF_SUBJECT_PUBLIC_KEY = 0x8A 68 | CKA_HASH_OF_ISSUER_PUBLIC_KEY = 0x8B 69 | CKA_NAME_HASH_ALGORITHM = 0x8C 70 | CKA_KEY_TYPE = 0x100 71 | CKA_SUBJECT = 0x101 72 | CKA_ID = 0x102 73 | CKA_SENSITIVE = 0x103 74 | CKA_ENCRYPT = 0x104 75 | CKA_DECRYPT = 0x105 76 | CKA_WRAP = 0x106 77 | CKA_UNWRAP = 0x107 78 | CKA_SIGN = 0x108 79 | CKA_SIGN_RECOVER = 0x109 80 | CKA_VERIFY = 0x10A 81 | CKA_VERIFY_RECOVER = 0x10B 82 | CKA_DERIVE = 0x10C 83 | CKA_START_DATE = 0x110 84 | CKA_END_DATE = 0x111 85 | CKA_MODULUS = 0x120 86 | CKA_MODULUS_BITS = 0x121 87 | CKA_PUBLIC_EXPONENT = 0x122 88 | CKA_PUBLIC_KEY_INFO = 0x129 89 | CKA_VALUE_LEN = 0x161 90 | CKA_EXTRACTABLE = 0x162 91 | CKA_LOCAL = 0x163 92 | CKA_NEVER_EXTRACTABLE = 0x164 93 | CKA_ALWAYS_SENSITIVE = 0x165 94 | CKA_KEY_GEN_MECHANISM = 0x166 95 | CKA_MODIFIABLE = 0x170 96 | CKA_COPYABLE = 0x171 97 | CKA_DESTROYABLE = 0x172 98 | CKA_EC_PARAMS = 0x180 99 | CKA_EC_POINT = 0x181 100 | CKA_ALWAYS_AUTHENTICATE = 0x202 101 | CKA_WRAP_WITH_TRUSTED = 0x210 102 | CKA_WRAP_TEMPLATE=0x40000211 103 | CKA_UNWRAP_TEMPLATE=0x40000212 104 | CKA_ALLOWED_MECHANISMS=0x40000600 105 | 106 | CKA_VENDOR_DEFINED=0x80000000 107 | CKA_VENDOR_TPM2_DEFINED=0x0F000000 108 | 109 | # We will allow these to be accessed, but the values are not stable 110 | CKA_TPM2_OBJAUTH_ENC=CKA_VENDOR_DEFINED|CKA_VENDOR_TPM2_DEFINED|0x1 111 | CKA_TPM2_PUB_BLOB=CKA_VENDOR_DEFINED|CKA_VENDOR_TPM2_DEFINED|0x2 112 | CKA_TPM2_PRIV_BLOB=CKA_VENDOR_DEFINED|CKA_VENDOR_TPM2_DEFINED|0x3 113 | CKA_TPM2_SERIALIZED_TR=CKA_VENDOR_DEFINED|CKA_VENDOR_TPM2_DEFINED|0x5 114 | 115 | CKC_X_509 = 0 116 | 117 | CK_SECURITY_DOMAIN_UNSPECIFIED = 0x0 118 | 119 | CK_CERTIFICATE_CATEGORY_UNSPECIFIED = 0x0 120 | -------------------------------------------------------------------------------- /tools/tpm2_pkcs11/tpm2_ptool.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-2-Clause 2 | from .command import commandlet 3 | 4 | # These imports are required to add the commandlet even though they appear unused 5 | # Store level commands 6 | from .commandlets_store import InitCommand # pylint: disable=unused-import # noqa 7 | from .commandlets_store import DestroyCommand # pylint: disable=unused-import # noqa 8 | 9 | # Token Level Commands 10 | from .commandlets_token import AddTokenCommand # pylint: disable=unused-import # noqa 11 | from .commandlets_token import AddEmptyTokenCommand # pylint: disable=unused-import # noqa 12 | from .commandlets_token import RmTokenCommand # pylint: disable=unused-import # noqa 13 | 14 | from .commandlets_token import VerifyCommand # pylint: disable=unused-import # noqa 15 | 16 | from .commandlets_token import InitPinCommand # pylint: disable=unused-import # noqa 17 | from .commandlets_token import ChangePinCommand # pylint: disable=unused-import # noqa 18 | 19 | from .commandlets_keys import AddKeyCommand # pylint: disable=unused-import # noqa 20 | from .commandlets_keys import ImportCommand # pylint: disable=unused-import # noqa 21 | 22 | 23 | def main(): 24 | '''The main entry point.''' 25 | 26 | commandlet.init('A tool for manipulating the tpm2-pkcs11 database') 27 | 28 | 29 | if __name__ == '__main__': 30 | main() 31 | -------------------------------------------------------------------------------- /tools/tpm2_ptool: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | "${PYTHON_INTERPRETER:-python3}" -m tpm2_pkcs11.tpm2_ptool "$@" 4 | -------------------------------------------------------------------------------- /tools/tpm2_ptool.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # SPDX-License-Identifier: BSD-2-Clause 3 | 4 | from tpm2_pkcs11 import tpm2_ptool as tool 5 | 6 | tool.main() 7 | --------------------------------------------------------------------------------