Projects
Eulaceura:Factory
tpm2-tss-engine
_service:obs_scm:tpm2-tss-engine-1684291576.28b...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:obs_scm:tpm2-tss-engine-1684291576.28be674.obscpio of Package tpm2-tss-engine
07070100000000000081A400000000000000000000000164643FF800000883000000000000000000000000000000000000003000000000tpm2-tss-engine-1684291576.28be674/CHANGELOG.md# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [1.2.0] - 2023-01-09 ### Fixed - Updated minimal version of tpm2-tss to 2.4.x - Fix encoding of emptyauth - Fix some memory leaks - Parent handle issues with signed representation by switching parent handle to BIGNUM. - Fixed RSA_NO_PADDING modes with OpenSSL 1.1.1 - Fixed autogen (bootstrap) call from release package by embedding VERSION file. ### Added - Use of restricted keys for signing - StirRandom - Run tests using swtpm - The ability to import key blobs from things like the tpm2-tools project. - Compatibility with openssl >=1.1.x - Support for ECDH - QNX support. - Only set -Werror for non-release builds. - Additional checks on TPM responses - CODE_OF_CONDUCT - SECURITY reporting instructions ## [1.1.0] - 2020-11-20 ### Added - Configure option for ptpm tests - Configure script AX_CHECK_ENABLE_DEBUG - Option for setting tcti on executable - TCTI-env variable used by default - Support for parent key passwords - openssl.cnf sample file ### Changed - Fix several build system, autotools and testing related issues Now adhere to CFLAGS conventions - Include pkg-config dependecy on libtss2-mu in order to work with tpm2-tss 2.3 - Enables parallel testing of integration tests: Make integration tests use TPM simulator; instead of first TPM it finds Use of different port numbers for TCP based tests - Fix EC param info (using named curve format) - Use tpm2-tools 4.X stable branch for integration tests - Use libtss2-tctildr.so instead of custom code for tcti setup - Fix manpages for -P/--parent option and correct engine name - Fix TCTI env variable handling ## [1.0.0] - 2019-04-04 ### Added - Initial release of the OpenSSL engine for TPM2.0 using the TCG's TPM Software Stack compliant tpm2-tss libraries. - tpm2tss (the engine) compatible against OpenSSL 1.0.2 and 1.1.0. - tpm2tss-genkey (cli-tool) for creating keys for use with the engine. - man-pages and bash-completion are included. 07070100000001000081A400000000000000000000000164643FF800001574000000000000000000000000000000000000003600000000tpm2-tss-engine-1684291576.28be674/CODE_OF_CONDUCT.md # Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at [MAINTAINERS](MAINTAINERS). All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations]. [homepage]: https://www.contributor-covenant.org [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html [Mozilla CoC]: https://github.com/mozilla/diversity [FAQ]: https://www.contributor-covenant.org/faq [translations]: https://www.contributor-covenant.org/translations 07070100000002000081A400000000000000000000000164643FF8000007AB000000000000000000000000000000000000003300000000tpm2-tss-engine-1684291576.28be674/CONTRIBUTING.md# Guidelines for submitting bugs: All non security bugs should be filed on the Issues tracker: https://github.com/tpm2-software/tpm2-tss-engine/issues Security sensitive bugs should follow the details in SECURITY.md. # Guideline for submitting changes: All changes to the source code must follow the coding standard used in the tpm2-tss project [here](https://github.com/tpm2-software/tpm2-tss/blob/master/doc/coding_standard_c.md). All changes should be introduced via github pull requests. This allows anyone to comment and provide feedback in lieu of having a mailing list. For pull requests opened by non-maintainers, any maintainer may review and merge that pull request. For maintainers, they either must have their pull request reviewed by another maintainer if possible, or leave the PR open for at least 24 hours, we consider this the window for comments. ## Patch requirements * All tests must pass on Travis CI for the merge to occur. * All changes must not introduce superfluous changes or whitespace errors. * All commits should adhere to the git commit message guidelines described here: https://chris.beams.io/posts/git-commit/ with the following exceptions. * We allow commit subject lines up to 80 characters. * All contributions must adhere to the Developers Certificate of Origin. The full text of the DCO is here: https://developercertificate.org/. Contributors must add a 'Signed-off-by' line to their commits. This indicates the submitters acceptance of the DCO. ## Guideline for merging changes Pull Requests MUST be assigned to an upcoming release tag. If a release milestone does not exist, the maintainer SHALL create it per the [RELEASE.md](RELEASE.md) instructions. When accepting and merging a change, the maintainer MUST edit the description field for the release milestone to add the CHANGELOG entry. Changes must be merged with the "rebase" option on github to avoid merge commits. This provides for a clear linear history. 07070100000003000081A400000000000000000000000164643FF8000005A3000000000000000000000000000000000000002B00000000tpm2-tss-engine-1684291576.28be674/LICENSERedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 07070100000004000081A400000000000000000000000164643FF80000006D000000000000000000000000000000000000002F00000000tpm2-tss-engine-1684291576.28be674/MAINTAINERSAndreas Fuchs <andreas.fuchs@sit.fraunhofer.de> Juergen Repp <juergen.repp@sit.fraunhofer.de> (occasionally) 07070100000005000081A400000000000000000000000164643FF8000020EC000000000000000000000000000000000000002F00000000tpm2-tss-engine-1684291576.28be674/Makefile.am#;*****************************************************************************; # Copyright (c) 2018 Fraunhofer SIT sponsored by Infineon Technologies AG # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # 3. Neither the name of tpm2-tss-engine nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. #;*****************************************************************************; ### Initialize global variables used throughout the file ### INCLUDE_DIRS = -I$(srcdir)/include -I$(srcdir)/src ACLOCAL_AMFLAGS = -I m4 --install AM_CFLAGS = $(INCLUDE_DIRS) $(EXTRA_CFLAGS) $(TSS2_ESYS_CFLAGS) \ $(TSS2_MU_CFLAGS) $(TSS2_TCTILDR_CFLAGS) $(CRYPTO_CFLAGS) \ $(CODE_COVERAGE_CFLAGS) AM_LDFLAGS = $(EXTRA_LDFLAGS) $(CODE_COVERAGE_LIBS) AM_LDADD = $(TSS2_ESYS_LIBS) $(TSS2_MU_LIBS) $(TSS2_TCTILDR_LIBS) \ $(CRYPTO_LIBS) AM_DISTCHECK_CONFIGURE_FLAGS = --with-enginesdir= --with-completionsdir= \ --enable-unit # Initialize empty variables to be extended throughout EXTRA_DIST = CLEANFILES = bin_PROGRAMS = ### Add ax_* rules ### # ax_code_coverage if AUTOCONF_CODE_COVERAGE_2019_01_06 include $(top_srcdir)/aminclude_static.am clean-local: code-coverage-clean distclean-local: code-coverage-dist-clean else @CODE_COVERAGE_RULES@ endif # ax_valgrind_check @VALGRIND_CHECK_RULES@ ### OpenSSL Engine ### openssl_enginedir = $(ENGINESDIR) openssl_engine_LTLIBRARIES = libtpm2tss.la include_HEADERS = include/tpm2-tss-engine.h libtpm2tss_la_SOURCES = src/tpm2-tss-engine.c \ src/tpm2-tss-engine-common.c \ src/tpm2-tss-engine-common.h \ src/tpm2-tss-engine-digest-sign.c \ src/tpm2-tss-engine-err.c \ src/tpm2-tss-engine-err.h \ src/tpm2-tss-engine-ecc.c \ src/tpm2-tss-engine-rand.c \ src/tpm2-tss-engine-rsa.c libtpm2tss_la_CFLAGS = $(AM_CFLAGS) libtpm2tss_la_LIBADD = $(AM_LDADD) libtpm2tss_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -avoid-version \ -export-symbols-regex '(tpm2tss*|bind_engine|v_check)' install-exec-local: ([ -e $(DESTDIR)$(openssl_enginedir) ] || \ $(MKDIR_P) $(DESTDIR)$(openssl_enginedir)) # Due to confusions with OpenSSL Naming conventions for engines regarding the # lib* prefix, we will create a symlink for the engine on install # see https://github.com/tpm2-software/tpm2-tss-engine/issues/6#issuecomment-422489744 # see https://github.com/openssl/openssl/commit/9ee0ed3de66678a15db126d10b3e4226e835b8f5 install-exec-hook: (cd $(DESTDIR)$(openssl_enginedir) && \ $(LN_S) -f libtpm2tss.so tpm2tss.so) uninstall-hook: (cd $(DESTDIR)$(openssl_enginedir) && \ [ -L tpm2tss.so ] && rm -f tpm2tss.so) ### KeyGenerator ### bin_PROGRAMS += tpm2tss-genkey tpm2tss_genkey_SOURCES = src/tpm2tss-genkey.c tpm2tss_genkey_CFLAGS = $(AM_CFLAGS) tpm2tss_genkey_LDADD = $(AM_LDADD) libtpm2tss.la tpm2tss_genkey_LDFLAGS = $(AM_LDFLAGS) ### Tests ### TESTS = $(TESTS_INTEGRATION) $(TESTS_UNIT) check_PROGRAMS = $(TESTS_UNIT) TESTS_UNIT = TESTS_INTEGRATION = if INTEGRATION TESTS_INTEGRATION += $(TESTS_SHELL) endif #INTEGRATION TESTS_SHELL = test/ecdsa.sh \ test/ecdsa-emptyauth.sh \ test/ecdsa-handle-flush.sh \ test/rand.sh \ test/rsadecrypt.sh \ test/rsasign.sh \ test/failload.sh \ test/failwrite.sh \ test/rsasign_importtpm.sh \ test/rsasign_importtpmparent.sh \ test/rsasign_parent.sh \ test/rsasign_parent_pass.sh \ test/rsasign_persistent.sh \ test/rsasign_persistent_emptyauth.sh \ test/sserver.sh \ test/sclient.sh if HAVE_OPENSSL_ECDH TESTS_SHELL += test/ecdh.sh endif if HAVE_OPENSSL_DIGEST_SIGN TESTS_SHELL += test/ecdsa-restricted.sh \ test/rsasign_restricted.sh endif EXTRA_DIST += $(TESTS_SHELL) test/neg-handle.pem TEST_EXTENSIONS = .sh SH_LOG_COMPILER = $(srcdir)/test/sh_log_compiler.sh SH_LOG_FLAGS = $(INTEGRATION_ARGS) EXTRA_DIST += $(SH_LOG_COMPILER) if UNIT TESTS_UNIT += test/error_tpm2-tss-engine-common test/tpm2-tss-engine-common test_error_tpm2_tss_engine_common_CFLAGS = $(AM_CFLAGS) $(CMOCKA_CFLAGS) test_error_tpm2_tss_engine_common_LDADD = $(AM_LDADD) $(CMOCKA_LIBS) test_error_tpm2_tss_engine_common_LDFLAGS = $(AM_LDFLAGS) -Wl,--wrap=Esys_Initialize test_error_tpm2_tss_engine_common_SOURCES = test/error_tpm2-tss-engine-common.c \ $(libtpm2tss_la_SOURCES) test_tpm2_tss_engine_common_CFLAGS = $(AM_CFLAGS) $(CMOCKA_CFLAGS) \ -DNEG_HANDLE_PEM=\"$(top_srcdir)/test/neg-handle.pem\" test_tpm2_tss_engine_common_LDADD = $(AM_LDADD) $(CMOCKA_LIBS) test_tpm2_tss_engine_common_LDFLAGS = $(AM_LDFLAGS) test_tpm2_tss_engine_common_SOURCES = test/tpm2-tss-engine-common.c \ $(libtpm2tss_la_SOURCES) endif #UNIT # Adding user and developer information EXTRA_DIST += \ CHANGELOG.md \ CONTRIBUTING.md \ INSTALL.md \ LICENSE \ README.md \ VERSION # Generate the AUTHORS file from git log AUTHORS: $(AM_V_GEN)git log --format='%aN <%aE>' | \ grep -v 'users.noreply.github.com' | sort -u > $@ EXTRA_DIST += AUTHORS CLEANFILES += AUTHORS if HAVE_MAN_PAGES ### Man Pages dist_man_MANS = \ man/man1/tpm2tss-genkey.1 \ man/man3/tpm2tss_tpm2data_write.3 \ man/man3/tpm2tss_rsa_makekey.3 \ man/man3/tpm2tss_rsa_genkey.3 \ man/man3/tpm2tss_ecc_makekey.3 \ man/man3/tpm2tss_ecc_genkey.3 \ man/man3/tpm2tss_ecc_getappdata.3 \ man/man3/tpm2tss_tpm2data_read.3 \ man/man3/tpm2tss_ecc_setappdata.3 endif if !HAVE_PANDOC # If pandoc is not enabled, we want to complain that you need pandoc for make dist, # so hook the target and complain. dist-hook: @(>&2 echo "You do not have pandoc, a requirement for the distribution of manpages") @exit 1 endif man/man3/tpm2tss_tpm2data_read.3: man/man3/tpm2tss_tpm2data_write.3 $(AM_V_GEN)(rm $@ 2>/dev/null || true) && ln -s tpm2tss_tpm2data_write.3 $@ man/man3/tpm2tss_ecc_setappdata.3: man/man3/tpm2tss_ecc_getappdata.3 $(AM_V_GEN)(rm $@ 2>/dev/null || true) && ln -s tpm2tss_ecc_getappdata.3 $@ man/man1/%.1: man/%.1.md $(AM_V_GEN)mkdir -p man/man1 && cat $< | $(PANDOC) -s -t man >$@ man/man3/%.3: man/%.3.md $(AM_V_GEN)mkdir -p man/man3 && cat $< | $(PANDOC) -s -t man >$@ EXTRA_DIST += \ man/tpm2tss-genkey.1.md \ man/tpm2tss_tpm2data_write.3.md \ man/tpm2tss_rsa_makekey.3.md \ man/tpm2tss_rsa_genkey.3.md \ man/tpm2tss_ecc_makekey.3.md \ man/tpm2tss_ecc_genkey.3.md \ man/tpm2tss_ecc_getappdata.3.md CLEANFILES += \ $(dist_man_MANS) ### Bash Completion bash_completiondir = $(completionsdir) bash_completion_DATA = bash-completion/tpm2tss-genkey EXTRA_DIST += bash-completion/tpm2tss-genkey 07070100000006000081A400000000000000000000000164643FF800001D87000000000000000000000000000000000000003000000000tpm2-tss-engine-1684291576.28be674/README.en.md[![Linux Build Status](https://github.com/tpm2-software/tpm2-tss-engine/workflows/Linux%20Build%20Status/badge.svg)](https://github.com/tpm2-software/tpm2-tss-engine/actions) [![Code Coverage](https://codecov.io/gh/tpm2-software/tpm2-tss-engine/branch/master/graph/badge.svg)](https://codecov.io/gh/tpm2-software/tpm2-tss-engine) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/tpm2-software/tpm2-tss-engine.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/tpm2-software/tpm2-tss-engine/context:cpp) [![Coverity Scan](https://img.shields.io/coverity/scan/22247.svg)](https://scan.coverity.com/projects/tpm2-tss-engine) # Overview The tpm2-tss-engine project implements a cryptographic engine for [OpenSSL](https://www.openssl.org) for [Trusted Platform Module (TPM 2.0)](https://trustedcomputinggroup.org/work-groups/trusted-platform-module/) using the [tpm2-tss](https://www.github.com/tpm2-software/tpm2-tss) software stack that follows the Trusted Computing Groups (TCG) [TPM Software Stack (TSS 2.0)](https://trustedcomputinggroup.org/work-groups/software-stack/). It uses the [Enhanced System API (ESAPI)](https://trustedcomputinggroup.org/wp-content/uploads/TSS_ESAPI_Version-0.9_Revision-04_reviewEND030918.pdf) interface of the TSS 2.0 for downwards communication. It supports RSA decryption and signatures as well as ECDSA signatures. If you are looking for a provider following the OpenSSL 3.0 provider API instead of the engine API, please head over to [tpm2-openssl](https://github.com/tpm2-software/tpm2-openssl) # Operations ## Key hierarchies The keys used by this engine are all located underneath an ECC restricted primary storage decryption key. This key is created on each invocation (since ECC key creation is faster than RSA's). Thus, no persistent SRK key need to be predeployed. The authorization value for the storage hierarchie (the owner password) is assumed to be clear (of zero length). If this is not the case, it needs to be set using the engine ctrl. ## Key types The RSA keys are created with the ability to sign as well as to decrypt. This allows all RSA keys to be used for either operation. Note: The TPM's RSA sign operation will enforce tagging payloads with an ASN.1 encoded identifier of the used hash algorithm. This is incompatible with OpelSSL's RSA interface structures. Thus, the TPM2_RSA_Decrypt method is also used for signing operations which also requires decrypt capabilities to be activated for this key. The ECDSA keys are created as ECDSA keys with the ability to perform signature operations. # Build and install instructions Instructions to build and install tpm2-tss are available in the [INSTALL](INSTALL.md) file. # Usage For additional usage examples, please consider the integration tests under `tests/*.sh`. ## Engine information Engine informations can be retrieved using ``` openssl engine -t -c tpm2tss ``` ## Random data A set of 10 random bytes can be retrieved using ``` openssl rand -engine tpm2tss -hex 10 engine "tpm2tss" set. WARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-default.so WARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-tabrmd.so 40ac9191079e490d17b7 WARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-default.so WARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-tabrmd.so ``` Note: These warnings stem from the tpm2-tss libraries and are not an issue, as long as a TPM connection is established afterwards by a different tcti. ## RSA operations ### RSA decrypt The following sequence of commands creates an RSA key using the TPM, exports the public key, encrypts a data file and decrypts it using the TPM: ``` tpm2tss-genkey -a rsa -s 2048 mykey openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub openssl pkeyutl -pubin -inkey mykey.pub -in mydata -encrypt -out mycipher openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -decrypt -in mycipher -out mydata ``` Alternatively, the data can be encrypted directly with the TPM key using: ``` openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -encrypt -in mydata -out mycipher ``` ### RSA sign The following sequence of commands creates an RSA key using the TPM, exports the public key, signs a data file using the TPM and validates the signature: ``` openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig openssl pkeyutl -pubin -inkey mykey.pub -verify -in mydata -sigfile mysig ``` Alternatively, the data can be validated directly using: `openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig` Note: `mydata` must not exceed the size of the RSA key, since these operation do not perform any hashing of the input data. ## ECDSA operations The following sequence of commands creates an ECDSA key using the TPM, signs a data file using the TPM and validates the signature: ``` tpm2tss-genkey -a ecdsa mykey openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig ``` To export the public key use: ``` openssl ec -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub ``` ## Self Signed certificate generate operation The following sequence of commands creates self signed certificate using TPM key. Openssl command sets tpm2tss as engine and generates a self signed certificate based on provided CSR configuration information. ``` $ tpm2tss-genkey -a rsa rsa.tss $ openssl req -new -x509 -engine tpm2tss -key rsa.tss -keyform engine -out rsa.crt ``` ## Signing using restricted key Signing using a restricted ECDSA key is possible with the caveat that the TPM must be used for the digest, so higher-level digest & sign operations must be used instead, e.g.: ``` $ openssl dgst -engine tpm2tss -keyform engine -sha256 -sign ${HANDLE} -out mysig mydata.txt ``` Where `${HANDLE}` is the TPM persistent handle ID for the restricted key created by an external tool (since tpm2tss-genkey doesn't support creating restricted keys). # TLS and s_server This engine can be used in all places where OpenSSL is used to create a TLS secure channel connection. You have can specify the command ``` ./tpm2tss-genkey -a rsa rsa.tss openssl req -new -x509 -engine tpm2tss -key rsa.tss -keyform engine -out rsa.crt openssl s_server -cert rsa.crt -key rsa.tss -keyform engine -engine tpm2tss -accept 8443 ``` For ECDSA keys however, the Hash algorithm needs to be specified because the TPM does not support SHA512. You can blacklisting SHA512 universally. That is possible via openssl.cnf. See the "SignatureAlgorithms" configuration file command on this page: https://www.openssl.org/docs/man1.1.1/man3/SSL_CONF_cmd.html Note: Usage of s_server with HSM-protected private keys is only supported on OpenSSL 1.1.0 and newer. ## Development prefixes In order to use this engine without `make install` for testing call: ``` export LD_LIBRAY_PATH=${TPM2TSS}/src/tss2-{tcti,mu,sys,esys}/.libs export PKG_CONFIG_PATH=$PWD/../tpm2-tss/lib ./bootstrap ./configure \ CFLAGS="-I$PWD/../tpm2-tss/include" \ LDFLAGS="-L$PWD/../tpm2-tss/src/tss2-{esys,sys,mu,tcti}/.libs" make make check ``` 07070100000007000081A400000000000000000000000164643FF8000016F6000000000000000000000000000000000000002D00000000tpm2-tss-engine-1684291576.28be674/README.mdtpm2-tss-engine # 介绍 这个tpm2-tss-engine工程为openssl实现对于可信平台模块(TPM2.0)引擎加密,调用满足TCG规则的tss协议栈. 它使用 TSS 2.0 的增强型系统 API (ESAPI) 接口进行向下通信。它支持 RSA 解密和签名以及 ECDSA 签名. 如果你想找到遵循OpenSSL3.0提供的API,而不是引擎的API,请转到这个项目tpm2-openssl(https://github.com/tpm2-software/tpm2-openssl). # 操作 ## 密钥层级 此引擎使用的密钥都位于 ECC 受限的主存储解密密钥下,此密钥在每次调用时创建 (因为 ECC 密钥创建速度比 RSA 快),因此,无需预先部署持久SRK密钥。 假定存储层次结构(所有者密码)的授权值是清楚的(长度为零)。 如果不是这种情况,则需要使用引擎 ctrl 进行设置 ## 密钥类型 创建 RSA 密钥时具有签名和解密功能,这允许所有 RSA 密钥用于任一操作. 注意:TPM 的 RSA 签名操作将使用所用哈希算法的 ASN.1 编码标识符强制标记有效负载. 这与OpelSSL的RSA接口结构不兼容。因此,TPM2_RSA_Decrypt方法也用于签名操作, 这也需要为此密钥激活解密功能。 ECDSA 密钥被创建为具有执行签名操作能力的 ECDSA 密钥 #编译和安装指令 编译和安装tpm2-tss-engine是可用的指令在 [INSTALL](INSTALL.md)文件中。 # 使用 为了更多的测试用力,请考虑`tests/*.sh`集成测试 For additional usage examples, please consider the integration tests under `tests/*.sh`. ## 查看引擎信息 可以使用检索引擎信息 ``` openssl engine -t -c tpm2tss ``` ## 生成随机数 检索使用一组10个随机数 ``` openssl rand -engine tpm2tss -hex 10 engine "tpm2tss" set. WARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-default.so WARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-tabrmd.so 40ac9191079e490d17b7 WARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-default.so WARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-tabrmd.so ``` 注意:这些警告源于tpm2-tss库且不是问题,只要之后由不同的tcti建立了TPM链接。 ## RSA操作 ### RSA加密 以下命令序列使用 TPM 创建 RSA 密钥,导出 公钥,加密数据文件并使用 TPM 解密: ``` tpm2tss-genkey -a rsa -s 2048 mykey openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub openssl pkeyutl -pubin -inkey mykey.pub -in mydata -encrypt -out mycipher openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -decrypt -in mycipher -out mydata ``` 或者,可以使用 TPM 密钥直接加密数据: ``` openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -encrypt -in mydata -out mycipher ``` ### RSA 签名 以下命令序列使用 TPM 创建 RSA 密钥,导出 公钥,使用 TPM 签署数据文件并验证签名: ``` openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig openssl pkeyutl -pubin -inkey mykey.pub -verify -in mydata -sigfile mysig ``` 可选的,可以直接使用验证数据 `openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig` 注意:'mydata'一定不能超过RSA密钥的大小,因为这些操作没有对数据执行任何的哈希 ## ECDSA 操作 以下命令序列使用 TPM 创建 ECDSA 密钥,符号 使用 TPM 并验证签名的数据文件: ``` tpm2tss-genkey -a ecdsa mykey openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig ``` 导出公钥使用: ``` openssl ec -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub ``` ## 自签名证书生成操作 以下命令序列使用 TPM 密钥创建自签名证书。Openssl 命令将 tpm2tss 设置为引擎, 并根据提供的 CSR 配置信息生成自签名证书。 ``` $ tpm2tss-genkey -a rsa rsa.tss $ openssl req -new -x509 -engine tpm2tss -key rsa.tss -keyform engine -out rsa.crt ``` ## 使用受限密钥签名 可以使用受限制的 ECDSA 密钥进行签名,但需要注意的是, TPM 必须用于摘要,因此必须改用更高级别的摘要和签名操作,例如: ``` $ openssl dgst -engine tpm2tss -keyform engine -sha256 -sign ${HANDLE} -out mysig mydata.txt ``` 其中$ {handle}是由外部工具创建的限制密钥的tpm持久句柄ID (因为tpm2tss-genkey不支持创建受限密钥)。 ## TLS和s_server 该引擎可用于使用OpenSSL创建TLS的所有地方 安全通道连接。您可以指定命令 ``` ./tpm2tss-genkey -a rsa rsa.tss openssl req -new -x509 -engine tpm2tss -key rsa.tss -keyform engine -out rsa.crt openssl s_server -cert rsa.crt -key rsa.tss -keyform engine -engine tpm2tss -accept 8443 ``` 但是,对于ECDSA密钥,需要指定哈希算法,因为TPM不支持SHA512。您可以普遍列入SHA512. 通过openssl.cnf可以做到这一点。请参阅此页面上的“ signaturealgorithms”配置文件命令: https://www.openssl.org/docs/man1.1.1/man3/SSL_CONF_cmd.html 注意:仅在OpenSSL 1.1.0和新版本上支持使用HSM保护的私钥的S_Server使用 ## 开发前缀 为了在没有“make install”的情况下使用这个引擎进行测试调用: ``` export LD_LIBRAY_PATH=${TPM2TSS}/src/tss2-{tcti,mu,sys,esys}/.libs export PKG_CONFIG_PATH=$PWD/../tpm2-tss/lib ./bootstrap ./configure \ CFLAGS="-I$PWD/../tpm2-tss/include" \ LDFLAGS="-L$PWD/../tpm2-tss/src/tss2-{esys,sys,mu,tcti}/.libs" make make check ``` 07070100000008000081A400000000000000000000000164643FF800001494000000000000000000000000000000000000002E00000000tpm2-tss-engine-1684291576.28be674/RELEASE.md# Release Process: This document describes the general process that maintainers must follow when making a release of the `tpm2-tss-engine` library and cli-tool. # Milestones All releases should have a milestone used to track the release. If the release version is not known, as covered in [Version Numbers](#Version Numbers), then an "x" may be used for the unknown number, or the generic term "next" may be used. The description field of the milestone will be used to record the CHANGELOG for that release. See [CHANGELOG Update](#CHANGELOG Update) for details. # Version Numbers This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). In summary: Given a version number MAJOR.MINOR.PATCH, increment the: 1. MAJOR version when you make incompatible API changes, 2. MINOR version when you add functionality in a backwards-compatible manner, and 3. PATCH version when you make backwards-compatible bug fixes. Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format. ## Version String The version string is set for the rest of the autotools bits by autoconf. Autoconf gets this string from the `AC_INIT` macro in the configure.ac file. Once you decide on the next version number (using the scheme above) you must set it manually in configure.ac. The version string must be in the form `A.B.C` where `A`, `B` and `C` are integers representing the major, minor and micro components of the version number. ## Release Candidates In the run up to a release the maintainers may create tags to identify progress toward the release. In these cases we will append a string to the release number to indicate progress using the abbreviation `rc` for 'release candidate'. This string will take the form of `-rcX`. We append an incremental digit `X` in case more than one release candidate is necessary to communicate progress as development moves forward. # CHANGELOG Update Before tagging the repository with the release version, the maintainer MUST update the CHANGELOG file with the contents from the description field from the corresponding release milestone and update any missing version string details in the CHANGELOG and milestone entry. # Git Tags When a release is made a tag is created in the git repo identifying the release by the [version string](#Version String). The tag should be pushed to upstream git repo as the last step in the release process. **NOTE** tags for release candidates will be deleted from the git repository after a release with the corresponding version number has been made. **NOTE** release (not release candidate) tags should be considered immutable. ## Signed tags Git supports GPG signed tags and releases will have tags signed by a maintainer. For details on how to sign and verify git tags see: https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work. # Release tarballs We use the git tag as a way to mark the point of the release in the projects history. We do not however encourage users to build from git unless they intend to modify the source code and contribute to the project. For the end user we provide release tarballs following the GNU conventions as closely as possible. To make a release tarball use the `distcheck` make target. This target includes a number of sanity checks that are extremely helpful. For more information on `automake` and release tarballs see: https://www.gnu.org/software/automake/manual/html_node/Dist.html#Dist ## Hosting Releases on Github Github automagically generates a page in their UI that maps git tags to 'releases' (even if the tag isn't for a release). Additionally they support hosting release tarballs through this same interface. The release tarball created in the previous step must be posted to github using the release interface. Additionally, this tarball must be accompanied by a detached GPG signature. The Debian wiki has an excellent description of how to post a signed release to Github here: https://wiki.debian.org/Creating%20signed%20GitHub%20releases **NOTE** release candidates must be taken down after a release with the corresponding version number is available. ## Signing Release Tarballs Signatures must be generated using the `--detach-sign` and `--armor` options to the `gpg` command. ## Verifying Signatures Verifying the signature on a release tarball requires the project maintainers public keys be installed in the GPG keyring of the verifier. With both the release tarball and signature file in the same directory the following command will verify the signature: ``` $ gpg --verify tpm2-tss-engine-X.Y.Z.tar.gz.asc ``` ## Signing Keys The GPG keys used to sign a release tag and the associated tarball must be the same. Additionally they must: * belong to a project maintainer * be discoverable using a public GPG key server * be associated with the maintainers github account (https://help.github.com/articles/adding-a-new-gpg-key-to-your-github-account/) # Announcements Release candidates and proper releases should be announced on the mailing list: - https://lists.linuxfoundation.org/mailman/listinfo/tpm2 This announcement should be accompanied by a link to the release page on Github as well as a link to the CHANGELOG.md accompanying the release. 07070100000009000081A400000000000000000000000164643FF80000061E000000000000000000000000000000000000002F00000000tpm2-tss-engine-1684291576.28be674/SECURITY.md# Security Policy ## Supported Versions Currently supported versions: | Version | Supported | | ------- | ------------------ | | any | :white_check_mark: | ## Reporting a Vulnerability ### Reporting Security vulnerabilities can be disclosed in one of two ways: - 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. - Email: A descirption *should be emailed* to **all** members of the [MAINTAINERS](MAINTAINERS) file to coordinate the disclosure of the vulnerability. ### Tracking When a maintainer is notified of a security vulnerability, they *must* create a GitHub security advisory per the instructions at: - <https://docs.github.com/en/code-security/repository-security-advisories/about-github-security-advisories-for-repositories> Maintainers *should* use the optional feature through GitHub to request a CVE be issued, alternatively RedHat has provided CVE's in the past and *may* be used, but preference is on GitHub as the issuing CNA. ### Publishing Once ready, maintainers should publish the security vulnerability as outlined in: - <https://docs.github.com/en/code-security/repository-security-advisories/publishing-a-repository-security-advisory> As well as ensuring the publishing of the CVE, maintainers *shal*l have new release versions ready to publish at the same time as the CVE. Maintainers *should* should strive to adhere to a sub 60 say turn around from report to release. 0707010000000A000041ED00000000000000000000000264643FF800000000000000000000000000000000000000000000003300000000tpm2-tss-engine-1684291576.28be674/bash-completion0707010000000B000081A400000000000000000000000164643FF80000042A000000000000000000000000000000000000004200000000tpm2-tss-engine-1684291576.28be674/bash-completion/tpm2tss-genkey_tpm2tss-genkey() { local cur prev opts COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" case "${prev}" in -a | --alg) COMPREPLY=( $(compgen -W "rsa ecdsa" -- ${cur}) ); return 0 ;; -c | --curve) COMPREPLY=( $(compgen -W "nist_p256" -- ${cur}) ); return 0 ;; -e | --exponent) COMPREPLY=( $(compgen -W "65537" -- ${cur}) ); return 0 ;; -o | --ownerpw | \ -p | --password) COMPREPLY="" return 0 ;; -s | --keysize) COMPREPLY=( $(compgen -W "2048" -- ${cur}) ); return 0 ;; -W | --parentpw) COMPREPLY="" return 0 ;; esac; opts="-a --alg -c --curve -e --exponent -h --help -o --ownerpw -p --password -s --keysize -v --verbose -W --parentpw" if [[ ${cur} = -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 fi COMPREPLY=( $(compgen -f ${cur}) ) } complete -F _tpm2tss-genkey tpm2tss-genkey 0707010000000C000081ED00000000000000000000000164643FF800000060000000000000000000000000000000000000002D00000000tpm2-tss-engine-1684291576.28be674/bootstrap#!/bin/bash set -e git describe --tags --always --dirty > VERSION autoreconf --install --sym 0707010000000D000081A400000000000000000000000164643FF800002985000000000000000000000000000000000000003000000000tpm2-tss-engine-1684291576.28be674/configure.ac#;*****************************************************************************; # Copyright (c) 2018 Fraunhofer SIT sponsored by Infineon Technologies AG # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # 3. Neither the name of tpm2-tss-engine nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. #;*****************************************************************************; AC_PREREQ([2.68]) AC_INIT([tpm2-tss-engine], [m4_esyscmd_s([cat ./VERSION])], [https://github.com/tpm2-software/tpm2-tss-engine/issues], [], [https://github.com/tpm2-software/tpm2-tss-engine]) dnl Let's be FHS-conform by default. if test "$prefix" = '/usr'; then test "$sysconfdir" = '${prefix}/etc' && sysconfdir="/etc" test "$sharedstatedir" = '${prefix}/com' && sharedstatedir="/var" test "$localstatedir" = '${prefix}/var' && localstatedir="/var" fi AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([src/tpm2-tss-engine.c]) AC_CONFIG_AUX_DIR([build-aux]) # propagate configure arguments to distcheck AC_SUBST([DISTCHECK_CONFIGURE_FLAGS],[$ac_configure_args]) AC_CANONICAL_SYSTEM AM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Wno-portability]) #Backward compatible setting of "silent-rules" m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AM_MAINTAINER_MODE([enable]) AX_IS_RELEASE([dash-version]) AX_CHECK_ENABLE_DEBUG([info]) AC_PROG_CC AC_PROG_CC_C99 AM_PROG_CC_C_O LT_INIT() AC_PROG_MKDIR_P AC_PROG_LN_S AC_CONFIG_HEADERS([src/config.h]) AC_ARG_ENABLE([tctienvvar], [AS_HELP_STRING([--disable-tctienvvar], [Disable setting the TCTI option from an environment variable])],, [enable_tctienvvar=yes]) AS_IF([test "x$enable_tctienvvar" = xyes], [AC_DEFINE([ENABLE_TCTIENVVAR], [1], 'Enable getting TCTI from env variable')]) AC_CONFIG_FILES([Makefile]) AC_ARG_ENABLE([defaultflags], [AS_HELP_STRING([--disable-defaultflags], [Disable default preprocessor, compiler, and linker flags.])],, [enable_defaultflags=yes]) AS_IF([test "x$enable_defaultflags" = "xyes"], [ AX_ADD_COMPILER_FLAG([-std=gnu99]) AX_ADD_COMPILER_FLAG([-Wall]) AX_ADD_COMPILER_FLAG([-Wextra]) AX_ADD_COMPILER_FLAG([-Wformat-security]) AS_IF([test "x$ax_is_release" = "xno"], [AX_ADD_COMPILER_FLAG([-Werror])]) AX_ADD_COMPILER_FLAG([-fstack-protector-all]) AX_ADD_COMPILER_FLAG([-fpic]) AX_ADD_COMPILER_FLAG([-fPIC]) # work around GCC bug #53119 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119 AX_ADD_COMPILER_FLAG([-Wno-missing-braces]) AX_ADD_LINK_FLAG([-Wl,--no-undefined]) AX_ADD_LINK_FLAG([-Wl,-z,noexecstack]) AX_ADD_LINK_FLAG([-Wl,-z,now]) AX_ADD_LINK_FLAG([-Wl,-z,relro]) ]) AX_CODE_COVERAGE m4_ifdef([_AX_CODE_COVERAGE_RULES], [AM_CONDITIONAL(AUTOCONF_CODE_COVERAGE_2019_01_06, [true])], [AM_CONDITIONAL(AUTOCONF_CODE_COVERAGE_2019_01_06, [false])]) AX_ADD_AM_MACRO_STATIC([]) PKG_PROG_PKG_CONFIG([0.25]) PKG_CHECK_MODULES([CRYPTO], [libcrypto >= 1.0.2g], [ac_enginesdir=`$PKG_CONFIG --variable=enginesdir libcrypto`]) PKG_CHECK_MODULES([TSS2_ESYS], [tss2-esys >= 2.3]) PKG_CHECK_MODULES([TSS2_MU], [tss2-mu]) PKG_CHECK_MODULES([TSS2_TCTILDR], [tss2-tctildr]) AC_CHECK_LIB([crypto], EC_KEY_METHOD_set_compute_key, [AM_CONDITIONAL([HAVE_OPENSSL_ECDH], true)], [AM_CONDITIONAL([HAVE_OPENSSL_ECDH], false)]) AC_CHECK_LIB([crypto], EVP_PKEY_meth_set_digest_custom, [AM_CONDITIONAL([HAVE_OPENSSL_DIGEST_SIGN], true)], [AM_CONDITIONAL([HAVE_OPENSSL_DIGEST_SIGN], false)]) AS_IF([test "x$ac_cv_lib_crypto_EVP_PKEY_meth_set_digest_custom" = xyes], [AC_DEFINE([HAVE_OPENSSL_DIGEST_SIGN], [1], Have required functionality from OpenSSL to support digest and sign)]) AC_PATH_PROG([PANDOC], [pandoc]) AS_IF([test -z "$PANDOC"], [AC_MSG_WARN([Required executable pandoc not found, man pages will not be built])]) AM_CONDITIONAL([HAVE_PANDOC],[test -n "$PANDOC"]) AM_CONDITIONAL([HAVE_MAN_PAGES],[test -d "${srcdir}/man/man1" -o -n "$PANDOC"]) AC_PATH_PROG([EXPECT], [expect]) AS_IF([test -z "$EXPECT"], [AC_MSG_WARN([Required executable expect not found, some tests might fail])]) AC_ARG_WITH([enginesdir], [AS_HELP_STRING([--with-enginesdir], [Set the OpenSSL engine directory (default: use pkg-config)])], [], [with_enginesdir=$ac_enginesdir]) AS_IF([test -z "$with_enginesdir"], [AC_MSG_WARN([Empty enginesdir, using $libdir/engines instead.])]) # This weirdness is necessary to enable distcheck via DISTCHECK_CONFIGURE_FLAGS AS_IF([test -z "$with_enginesdir"], [with_enginesdir=$libdir/engines]) AC_SUBST(ENGINESDIR, "$with_enginesdir") AC_ARG_WITH([completionsdir], [AS_HELP_STRING([--with-completionsdir], [Set the bash completions directory (default: use pkg-config)])], [], [with_completionsdir=`$PKG_CONFIG --variable=completionsdir bash-completion`]) AS_IF([test -z "$with_completionsdir"], [AC_MSG_WARN([Empty completionsdir, using $datarootdir/bash-completion/completions instead.])]) AS_IF([test -z "$with_completionsdir"], [with_completionsdir=$datarootdir/bash-completion/completions]) AC_SUBST(completionsdir, "$with_completionsdir") AC_ARG_ENABLE([unit], [AS_HELP_STRING([--enable-unit], [build cmocka unit tests])],, [enable_unit=no]) AS_IF([test "x$enable_unit" != "xno" ], [PKG_CHECK_MODULES([CMOCKA], [cmocka >= 1.0])]) AM_CONDITIONAL([UNIT], [test "x$enable_unit" != xno]) AC_ARG_ENABLE([integration], [AS_HELP_STRING([--enable-integration], [build integration tests against TPM])],, [enable_integration=no]) AM_CONDITIONAL([INTEGRATION], [test "x$enable_integration" != xno]) # Use physical TPM device for testing AC_ARG_WITH([device], [AS_HELP_STRING([--with-device=<device>],[TPM device for testing])], [AS_IF([test \( -w "$with_device" \) -a \( -r "$with_device" \)], [AC_MSG_RESULT([success]) AX_NORMALIZE_PATH([with_device]) with_device_set=yes], [AC_MSG_ERROR([TPM device provided does not exist or is not writable])])], [with_device_set=no]) AM_CONDITIONAL([TESTDEVICE],[test "x$with_device_set" = xyes]) AC_CHECK_FUNC([backtrace_symbols_fd],[AC_DEFINE([HAVE_EXECINFO],[1], ['Define to 1 if you have the <execinfo.h> header file.'])]) # Integration test with simulator AS_IF([test "x$enable_integration" = xyes && test "x$with_device_set" = xno], [integration_args="" AC_CHECK_PROG([tpm2_startup], [tpm2_startup], [yes]) AS_IF([test "x$tpm2_startup" != xyes], [AC_MSG_ERROR([Integration tests require the tpm2_startup executable])]) AC_CHECK_PROG([swtpm], [swtpm], [yes]) AC_CHECK_PROG([tpm_server], [tpm_server], [yes]) AS_IF([test "x$swtpm" != xyes && test "x$tpm_server" != xyes], [AC_MSG_ERROR([Integration tests require either the swtpm or the tpm_server executable])]) AC_CHECK_PROG([realpath], [realpath], [yes]) AS_IF([test "x$realpath" != xyes], [AC_MSG_ERROR([Integration tests require the realpath executable])]) AC_CHECK_PROG([ss], [ss], [yes]) AS_IF([test "x$ss" != xyes], [AC_MSG_ERROR([Integration tests require the ss executable])]) AS_IF([test "x$enable_tctienvvar" != xyes], [AC_MSG_ERROR([Integration tests require building with TCTI environment variable support])]) AC_SUBST([INTEGRATION_ARGS], [$integration_args]) ]) # Integration test with physical device AS_IF([test "x$enable_integration" = xyes && test "x$with_device_set" = xyes ], [integration_args="$with_device" AC_CHECK_PROG([realpath], [realpath], [yes]) AS_IF([test "x$realpath" != xyes], [AC_MSG_ERROR([Integration tests require the realpath executable])]) AS_IF([test "x$enable_tctienvvar" != xyes], [AC_MSG_ERROR([Integration tests require building with TCTI environment variable support])]) AC_SUBST([INTEGRATION_ARGS], [$integration_args]) ]) AX_VALGRIND_CHECK # # sanitizer compiler flags # AC_ARG_WITH([sanitizer], [AS_HELP_STRING([--with-sanitizer={none,address,undefined}], [build with the given sanitizer])],, [with_sanitizer=none]) AS_CASE(["x$with_sanitizer"], ["xnone"], [], ["xaddress"], [ SANITIZER_CFLAGS="-fsanitize=address -fno-omit-frame-pointer" SANITIZER_LDFLAGS="-lasan" ], ["xundefined"], [ SANITIZER_CFLAGS="-fsanitize=undefined" SANITIZER_LDFLAGS="-lubsan" ], [AC_MSG_ERROR([Bad value for --with-sanitizer])]) AC_SUBST([SANITIZER_CFLAGS]) AC_SUBST([SANITIZER_LDFLAGS]) AC_OUTPUT AC_MSG_RESULT([ $PACKAGE_NAME $VERSION man-pages: $PANDOC enginesdir: $with_enginesdir completionsdir: $with_completionsdir device: $with_device ]) 0707010000000E000041ED00000000000000000000000264643FF800000000000000000000000000000000000000000000002B00000000tpm2-tss-engine-1684291576.28be674/include0707010000000F000081A400000000000000000000000164643FF800000D95000000000000000000000000000000000000003D00000000tpm2-tss-engine-1684291576.28be674/include/tpm2-tss-engine.h/******************************************************************************* * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of tpm2-tss-engine nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #ifndef TPM2_TSS_ENGINE_H #define TPM2_TSS_ENGINE_H #include <openssl/engine.h> #include <tss2/tss2_tpm2_types.h> #ifdef __cplusplus extern "C" { #endif typedef enum { KEY_TYPE_BLOB, KEY_TYPE_HANDLE } KEY_TYPE; typedef struct { int emptyAuth; TPM2B_DIGEST userauth; TPM2B_PUBLIC pub; TPM2_HANDLE parent; KEY_TYPE privatetype; union { TPM2B_PRIVATE priv; TPM2_HANDLE handle; }; } TPM2_DATA; #define TPM2TSS_SET_OWNERAUTH ENGINE_CMD_BASE #define TPM2TSS_SET_TCTI (ENGINE_CMD_BASE + 1) #define TPM2TSS_SET_PARENTAUTH (ENGINE_CMD_BASE + 2) int tpm2tss_tpm2data_write(const TPM2_DATA *tpm2data, const char *filename); int tpm2tss_tpm2data_read(const char *filename, TPM2_DATA **tpm2Datap); int tpm2tss_tpm2data_readtpm(uint32_t handle, TPM2_DATA **tpm2Datap); int tpm2tss_tpm2data_importtpm(const char *filenamepub, const char *filenametpm, TPM2_HANDLE parent, int emptyAuth, TPM2_DATA **tpm2Datap); EVP_PKEY * tpm2tss_rsa_makekey(TPM2_DATA *tpm2Data); int tpm2tss_rsa_genkey(RSA *rsa, int bits, BIGNUM *e, char *password, TPM2_HANDLE parentHandle); EVP_PKEY * tpm2tss_ecc_makekey(TPM2_DATA *tpm2Data); int tpm2tss_ecc_genkey(EC_KEY *key, TPMI_ECC_CURVE curve, const char *password, TPM2_HANDLE parentHandle); TPM2_DATA * #if OPENSSL_VERSION_NUMBER < 0x10100000 tpm2tss_ecc_getappdata(EC_KEY *key); #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ tpm2tss_ecc_getappdata(const EC_KEY *key); #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ int tpm2tss_ecc_setappdata(EC_KEY *key, TPM2_DATA *data); #ifdef __cplusplus } #endif #endif /* TPM2_TSS_ENGINE_H */ 07070100000010000041ED00000000000000000000000264643FF800000000000000000000000000000000000000000000002600000000tpm2-tss-engine-1684291576.28be674/m407070100000011000081A400000000000000000000000164643FF800000910000000000000000000000000000000000000002F00000000tpm2-tss-engine-1684291576.28be674/m4/flags.m4dnl AX_ADD_COMPILER_FLAG: dnl A macro to add a CFLAG to the EXTRA_CFLAGS variable. This macro will dnl check to be sure the compiler supports the flag. Flags can be made dnl mandatory (configure will fail). dnl $1: C compiler flag to add to EXTRA_CFLAGS. dnl $2: Set to "required" to cause configure failure if flag not supported. AC_DEFUN([AX_ADD_COMPILER_FLAG],[ AX_CHECK_COMPILE_FLAG([$1],[ EXTRA_CFLAGS="$EXTRA_CFLAGS $1" AC_SUBST([EXTRA_CFLAGS])],[ AS_IF([test x$2 != xrequired],[ AC_MSG_WARN([Optional CFLAG "$1" not supported by your compiler, continuing.])],[ AC_MSG_ERROR([Required CFLAG "$1" not supported by your compiler, aborting.])] )],[ -Wall -Werror] )] ) dnl AX_ADD_PREPROC_FLAG: dnl Add the provided preprocessor flag to the EXTRA_CFLAGS variable. This dnl macro will check to be sure the preprocessor supports the flag. dnl The flag can be made mandatory by providing the string 'required' as dnl the second parameter. dnl $1: Preprocessor flag to add to EXTRA_CFLAGS. dnl $2: Set to "required" t ocause configure failure if preprocesor flag dnl is not supported. AC_DEFUN([AX_ADD_PREPROC_FLAG],[ AX_CHECK_PREPROC_FLAG([$1],[ EXTRA_CFLAGS="$EXTRA_CFLAGS $1" AC_SUBST([EXTRA_CFLAGS])],[ AS_IF([test x$2 != xrequired],[ AC_MSG_WARN([Optional preprocessor flag "$1" not supported by your compiler, continuing.])],[ AC_MSG_ERROR([Required preprocessor flag "$1" not supported by your compiler, aborting.])] )],[ -Wall -Werror] )] ) dnl AX_ADD_LINK_FLAG: dnl A macro to add a LDLAG to the EXTRA_LDFLAGS variable. This macro will dnl check to be sure the linker supports the flag. Flags can be made dnl mandatory (configure will fail). dnl $1: linker flag to add to EXTRA_LDFLAGS. dnl $2: Set to "required" to cause configure failure if flag not supported. AC_DEFUN([AX_ADD_LINK_FLAG],[ AX_CHECK_LINK_FLAG([$1],[ EXTRA_LDFLAGS="$EXTRA_LDFLAGS $1" AC_SUBST([EXTRA_LDFLAGS])],[ AS_IF([test x$2 != xrequired],[ AC_MSG_WARN([Optional LDFLAG "$1" not supported by your linker, continuing.])],[ AC_MSG_ERROR([Required LDFLAG "$1" not supported by your linker, aborting.])] )] )] ) 07070100000012000041ED00000000000000000000000264643FF800000000000000000000000000000000000000000000002700000000tpm2-tss-engine-1684291576.28be674/man07070100000013000081A400000000000000000000000164643FF800000EE3000000000000000000000000000000000000003B00000000tpm2-tss-engine-1684291576.28be674/man/tpm2tss-genkey.1.md% tpm2tss-genkey(1) tpm2-tss-engine | General Commands Manual % % OCTOBER 2020 # NAME **tpm2tss-genkey**(1) -- generate TPM keys for tpm2-tss-engine # SYNOPSIS **tpm2tss-genkey** [*options*] <*filename*> # DESCRIPTION **tpm2tss-genkey** creates a key inside a TPM 2.0 connected via the tpm2tss software stack. Those keys may be an RSA key for decryption or signing or an ECC key for ECDSA signatures. The tool respects the OPENSSL_CONF option for specifying engine specific control parameters. See `man(5) config` for details on openssl config files. # ARGUMENTS The `tpm2tss-genkey` command expects a filename for storing the resulting TPM key information. This file can then be loaded with OpenSSL using `openssl pkeyutl -engine tpm2tss -keyform engine -inkey <filename>`. # OPTIONS * `-a <algorithm>`, `--alg <algorithm>`: The public key algorithm (rsa, ecdsa) (default: rsa) * `-c <curve>`, `--curve <curve>`: If alg ecdsa is chosen, the curve for ecc (default: nist_p256) * `-u <file>`, `--public <file>`: Public key (TPM2B_PUBLIC) to be imported. Requires `-r`. * `-r <file>`, `--private <file>`: The (encrypted) private key (TPM2B_PRIVATE) to be imported. Requires `-u`. * `-e <exponent>`, `--exponent <exponent>`: If alg rsa is chosen, the exponent for rsa (default: 65537) * `-h`, `--help`: Print help * `-o <password>`, `--ownerpw <password>`: Password for the owner hierarchy (default: none) Openssl Config control command: `SET_OWNERAUTH` * `-p <password>`, `--password <password>`: Password for the created key (default: none) * `-P <handle>`, `--parent <handle>`: Specific handle for the parent key (default: none) * `-s <keysize>`, `--keysize <keysize>`: If alg rsa is chosen, the key size in bits (default: 2048) * `-v`, `--verbose`: Print verbose messages * `-W <password>`, `--parentpw <password>`: Password for the parent key (default: none) Openssl Config control command: `SET_PARENTAUTH` * `-t <tcti-conf>`, `--tcti <tcti-conf>`: TCTI Configuration string (default: none) Openssl Config control command: `SET_TCTI` # EXAMPLES Engine information can be retrieved using: ``` $ openssl engine -t -c tpm2tss ``` The following sequence of commands creates an RSA key using the TPM, exports the public key, encrypts a data file and decrypts it using the TPM: ``` $ tpm2tss-genkey -a rsa -s 2048 mykey $ openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub $ openssl pkeyutl -pubin -inkey mykey.pub -in mydata -encrypt -out mycipher $ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -decrypt -in mycipher -out mydata ``` The following sequence of commands creates an RSA key using the TPM, exports the public key, signs a data file using the TPM and validates the signature: ``` $ tpm2tss-genkey -a rsa -s 2048 mykey $ openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub $ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig $ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig ``` The following sequence of commands creates an ECDSA key using the TPM, exports the public key, signs a data file using the TPM and validates the signature: ``` $ tpm2tss-genkey -a ecdsa -c nist_p256 mykey $ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig $ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig ``` # RETURNS 0 on success or 1 on failure. ## AUTHOR Written by Andreas Fuchs. ## COPYRIGHT tpm2tss is Copyright (C) 2017-2018 Fraunhofer SIT sponsored by Infineon Technologies AG. License BSD 3-clause. ## SEE ALSO openssl(1) 07070100000014000081A400000000000000000000000164643FF8000002DD000000000000000000000000000000000000003F00000000tpm2-tss-engine-1684291576.28be674/man/tpm2tss_ecc_genkey.3.md% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls % % JUNE 2018 # NAME **tpm2tss_ecc_genkey** -- Make an ECC key object # SYNOPSIS **#include <tpm2tss.h>** **int tpm2tss_ecc_genkey(EC_KEY *key, TPMI_ECC_CURVE curve, const char *password);** # DESCRIPTION **tpm2tss_ECC_genkey** issues the generation of an ECC key `key` using the TPM. The ECC curve is determined by `curve`. The new key will be protected by `password`. # RETURN VALUE Upon successful completion **tpm2tss_ecc_genkey**() returns 1. Otherwise 0. ## AUTHOR Written by Andreas Fuchs. ## COPYRIGHT tpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon Technologies AG. License BSD 3-clause. ## SEE ALSO openssl(1), tpm2tss_genkey(1) 07070100000015000081A400000000000000000000000164643FF8000002DA000000000000000000000000000000000000004300000000tpm2-tss-engine-1684291576.28be674/man/tpm2tss_ecc_getappdata.3.md% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls % % JUNE 2018 # NAME **tpm2tss_ecc_getappdata**, **tpm2tss_ecc_setappdata** -- Make an ECC key object # SYNOPSIS **#include <tpm2tss.h>** **TPM2_DATA * tpm2tss_ecc_getappdata(const EC_KEY *key);** **int tpm2tss_ecc_setappdata(EC_KEY *key, TPM2_DATA *data);** # DESCRIPTION **tpm2tss_ecc_getappdata** **tpm2tss_ecc_setappdata** # RETURN VALUE Upon successful completion **tpm2tss_ecc_getappdata**() and **tpm2tss_ecc_setappdata**() return 1. Otherwise 0. ## AUTHOR Written by Andreas Fuchs. ## COPYRIGHT tpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon Technologies AG. License BSD 3-clause. ## SEE ALSO openssl(1), tpm2tss_genkey(1) 07070100000016000081A400000000000000000000000164643FF8000002A6000000000000000000000000000000000000004000000000tpm2-tss-engine-1684291576.28be674/man/tpm2tss_ecc_makekey.3.md% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls % % JUNE 2018 # NAME **tpm2tss_ecc_makekey** -- Make an ECC key object # SYNOPSIS **#include <tpm2tss.h>** **EVP_PKEY * tpm2tss_ecc_makekey(TPM2_DATA *tpm2Data);** # DESCRIPTION **tpm2tss_ecc_makekey** takes a TPM2_DATA object as `tpm2Data` and creates a corresponding OpenSSL EVP_PKEY object. # RETURN VALUE Upon successful completion **tpm2tss_ecc_makekey**() returns the created EVP_PKEY object's pointer. Otherwise NULL. ## AUTHOR Written by Andreas Fuchs. ## COPYRIGHT tpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon Technologies AG. License BSD 3-clause. ## SEE ALSO openssl(1) 07070100000017000081A400000000000000000000000164643FF8000002F5000000000000000000000000000000000000003F00000000tpm2-tss-engine-1684291576.28be674/man/tpm2tss_rsa_genkey.3.md% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls % % JUNE 2018 # NAME **tpm2tss_rsa_genkey** -- Make an RSA key object # SYNOPSIS **#include <tpm2tss.h>** **int tpm2tss_rsa_genkey(RSA *rsa, int bits, BIGNUM *e, char *password);** # DESCRIPTION **tpm2tss_rsa_genkey** issues the generation of an RSA key `rsa` using the TPM. The keylength is determined by `bits`. The exponent is determined by `e`. The new key will be protected by `password`. # RETURN VALUE Upon successful completion **tpm2tss_rsa_genkey**() returns 1. Otherwise 0. ## AUTHOR Written by Andreas Fuchs. ## COPYRIGHT tpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon Technologies AG. License BSD 3-clause. ## SEE ALSO openssl(1), tpm2tss_genkey(1) 07070100000018000081A400000000000000000000000164643FF8000002A6000000000000000000000000000000000000004000000000tpm2-tss-engine-1684291576.28be674/man/tpm2tss_rsa_makekey.3.md% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls % % JUNE 2018 # NAME **tpm2tss_rsa_makekey** -- Make an RSA key object # SYNOPSIS **#include <tpm2tss.h>** **EVP_PKEY * tpm2tss_rsa_makekey(TPM2_DATA *tpm2Data);** # DESCRIPTION **tpm2tss_rsa_makekey** takes a TPM2_DATA object as `tpm2Data` and creates a corresponding OpenSSL EVP_PKEY object. # RETURN VALUE Upon successful completion **tpm2tss_rsa_makekey**() returns the created EVP_PKEY object's pointer. Otherwise NULL. ## AUTHOR Written by Andreas Fuchs. ## COPYRIGHT tpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon Technologies AG. License BSD 3-clause. ## SEE ALSO openssl(1) 07070100000019000081A400000000000000000000000164643FF8000003EE000000000000000000000000000000000000004300000000tpm2-tss-engine-1684291576.28be674/man/tpm2tss_tpm2data_write.3.md% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls % % JUNE 2018 # NAME **tpm2tss_tpm2data_write**, **tpm2tss_tpm2data_read** -- read/write TPM2_DATA # SYNOPSIS **#include <tpm2tss.h>** **int tpm2tss_tpm2data_read(const char *filename, TPM2_DATA **tpm2Datap);** **int tpm2tss_tpm2data_write(const TPM2_DATA *tpm2Data, const char *filename);** # DESCRIPTION **tpm2tss_tpm2data_read** reads the TPM2_DATA object from a file called `filename`, allocates memory and stores it under the parameter `tpm2Datap`. Must be freed using the `free()` function. **tpm2tss_tpm2data_write** writes the TPM2_DATA object from the parameter `tpm2Data` to a newly created file called `filename`. # RETURN VALUE Upon successful completion **tpm2tss_tpm2data_write**() and **tpm2tss_tpm2data_read**() return 1. Otherwise 0. ## AUTHOR Written by Andreas Fuchs. ## COPYRIGHT tpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon Technologies AG. License BSD 3-clause. ## SEE ALSO openssl(1) 0707010000001A000081A400000000000000000000000164643FF8000001C7000000000000000000000000000000000000003700000000tpm2-tss-engine-1684291576.28be674/openssl.conf.sampleopenssl_conf = openssl_init [openssl_init] engines = engine_section [engine_section] tpm2tss = tpm2tss_section [tpm2tss_section] engine_id = tpm2tss dynamic_path = /usr/lib/engines-1.1/libtpm2tss.so default_algorithms = RSA,ECDSA init = 1 #SET_TCTI = <TCTI_options> #SET_OWNERAUTH = <could_set_password_here, but then it's readable> #SET_PARENTAUTH = <password_of_parent_key> [req] distinguished_name = subject [subject] # prompts and defaults here 0707010000001B000041ED00000000000000000000000264643FF800000000000000000000000000000000000000000000002700000000tpm2-tss-engine-1684291576.28be674/src0707010000001C000081ED00000000000000000000000164643FF800005BC6000000000000000000000000000000000000004000000000tpm2-tss-engine-1684291576.28be674/src/tpm2-tss-engine-common.c/******************************************************************************* * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG * All rights reserved. * Copyright (c) 2019, Wind River Systems. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of tpm2-tss-engine nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #include <stdio.h> #include <string.h> #include <tss2/tss2_tctildr.h> #include <openssl/engine.h> #include <openssl/pem.h> #include <openssl/rand.h> #include "tpm2-tss-engine.h" #include "tpm2-tss-engine-common.h" ASN1_SEQUENCE(TSSPRIVKEY) = { ASN1_SIMPLE(TSSPRIVKEY, type, ASN1_OBJECT), ASN1_EXP_OPT(TSSPRIVKEY, emptyAuth, ASN1_BOOLEAN, 0), ASN1_SIMPLE(TSSPRIVKEY, parent, ASN1_INTEGER), ASN1_SIMPLE(TSSPRIVKEY, pubkey, ASN1_OCTET_STRING), ASN1_SIMPLE(TSSPRIVKEY, privkey, ASN1_OCTET_STRING) } ASN1_SEQUENCE_END(TSSPRIVKEY) #define TSSPRIVKEY_PEM_STRING "TSS2 PRIVATE KEY" IMPLEMENT_ASN1_FUNCTIONS(TSSPRIVKEY); IMPLEMENT_PEM_write_bio(TSSPRIVKEY, TSSPRIVKEY, TSSPRIVKEY_PEM_STRING, TSSPRIVKEY); IMPLEMENT_PEM_read_bio(TSSPRIVKEY, TSSPRIVKEY, TSSPRIVKEY_PEM_STRING, TSSPRIVKEY); /** Initialize the Esys context * * Initialize an Esys context. * @param esys_ctx The context to initialize. * @retval TSS2_RC_SUCCESS on success * @retval TSS2_BASE_RC_BAD_REFERENCE if no pointer was provided * @retval Errors from Tcti initialization or Esys_Initialize() */ TSS2_RC esys_ctx_init(ESYS_CONTEXT **esys_ctx) { TSS2_RC r; if (!esys_ctx) { ERR(esys_ctx_init, TPM2TSS_R_GENERAL_FAILURE); r = TSS2_BASE_RC_BAD_REFERENCE; } else { TSS2_TCTI_CONTEXT *tcti_ctx = NULL; r = Tss2_TctiLdr_Initialize(tcti_nameconf, &tcti_ctx); if (TSS2_RC_SUCCESS != r) { ERR(esys_ctx_init, TPM2TSS_R_GENERAL_FAILURE); } else { r = Esys_Initialize(esys_ctx, tcti_ctx, NULL); if (TSS2_RC_SUCCESS != r) { ERR(esys_ctx_init, TPM2TSS_R_GENERAL_FAILURE); Tss2_TctiLdr_Finalize(&tcti_ctx); } } } return r; } /** Finalize the Esys context * * Get the TCTI context and finalize this alongside the Esys context. * @param esys_ctx The Esys context * @retval TSS2_RC_SUCCESS on success * @retval TSS2_BASE_RC_BAD_REFERENCE if no pointer was provided * @retval Errors from Esys_GetTcti() */ TSS2_RC esys_ctx_free(ESYS_CONTEXT **esys_ctx) { TSS2_RC r; if ((!esys_ctx) || (!*esys_ctx)) { ERR(esys_ctx_free, TPM2TSS_R_GENERAL_FAILURE); r = TSS2_BASE_RC_BAD_REFERENCE; } else { TSS2_TCTI_CONTEXT *tcti_ctx; r = Esys_GetTcti(*esys_ctx, &tcti_ctx); Esys_Finalize(esys_ctx); if (TSS2_RC_SUCCESS != r) { ERR(esys_ctx_free, TPM2TSS_R_GENERAL_FAILURE); } else { Tss2_TctiLdr_Finalize(&tcti_ctx); } } return r; } /** Serialize tpm2data onto disk * * Write the tpm2tss key data into a file using PEM encoding. * @param tpm2Data The data to be written to disk. * @param filename The filename to write the data to. * @retval 1 on success * @retval 0 on failure */ int tpm2tss_tpm2data_write(const TPM2_DATA *tpm2Data, const char *filename) { TSS2_RC r; BIO *bio = NULL; TSSPRIVKEY *tpk = NULL; BIGNUM *bn_parent = NULL; uint8_t privbuf[sizeof(tpm2Data->priv)]; uint8_t pubbuf[sizeof(tpm2Data->pub)]; size_t privbuf_len = 0, pubbuf_len = 0; if ((bio = BIO_new_file(filename, "w")) == NULL) { ERR(tpm2tss_tpm2data_write, TPM2TSS_R_FILE_WRITE); goto error; } tpk = TSSPRIVKEY_new(); if (!tpk) { ERR(tpm2tss_tpm2data_write, ERR_R_MALLOC_FAILURE); goto error; } r = Tss2_MU_TPM2B_PRIVATE_Marshal(&tpm2Data->priv, &privbuf[0], sizeof(privbuf), &privbuf_len); if (r) { ERR(tpm2tss_tpm2data_write, TPM2TSS_R_DATA_CORRUPTED); goto error; } r = Tss2_MU_TPM2B_PUBLIC_Marshal(&tpm2Data->pub, &pubbuf[0], sizeof(pubbuf), &pubbuf_len); if (r) { ERR(tpm2tss_tpm2data_write, TPM2TSS_R_DATA_CORRUPTED); goto error; } tpk->type = OBJ_txt2obj(OID_loadableKey, 1); tpk->parent = ASN1_INTEGER_new(); tpk->privkey = ASN1_OCTET_STRING_new(); tpk->pubkey = ASN1_OCTET_STRING_new(); if (!tpk->type || !tpk->privkey || !tpk->pubkey || !tpk->parent) { ERR(tpm2tss_tpm2data_write, ERR_R_MALLOC_FAILURE); goto error; } tpk->emptyAuth = tpm2Data->emptyAuth ? 0xFF : 0; bn_parent = BN_new(); if (!bn_parent) { goto error; } if (tpm2Data->parent != 0) { BN_set_word(bn_parent, tpm2Data->parent); } else { BN_set_word(bn_parent, TPM2_RH_OWNER); } BN_to_ASN1_INTEGER(bn_parent, tpk->parent); ASN1_STRING_set(tpk->privkey, &privbuf[0], privbuf_len); ASN1_STRING_set(tpk->pubkey, &pubbuf[0], pubbuf_len); PEM_write_bio_TSSPRIVKEY(bio, tpk); TSSPRIVKEY_free(tpk); BIO_free(bio); return 1; error: if (bio) BIO_free(bio); if (tpk) TSSPRIVKEY_free(tpk); return 0; } /** Create tpm2data from a TPM key * * Retrieve the public key of tpm2data from the TPM for a given handle. * @param handle The TPM's key handle. * @param tpm2Datap The data after read. * @retval 1 on success * @retval 0 on failure */ int tpm2tss_tpm2data_readtpm(uint32_t handle, TPM2_DATA **tpm2Datap) { TSS2_RC r; TPM2_DATA *tpm2Data = NULL; ESYS_TR keyHandle = ESYS_TR_NONE; ESYS_CONTEXT *esys_ctx = NULL; TPM2B_PUBLIC *outPublic; tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data)); if (tpm2Data == NULL) { ERR(tpm2tss_tpm2data_readtpm, ERR_R_MALLOC_FAILURE); goto error; } memset(tpm2Data, 0, sizeof(*tpm2Data)); tpm2Data->privatetype = KEY_TYPE_HANDLE; tpm2Data->handle = handle; r = esys_ctx_init(&esys_ctx); if (r) { ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE); goto error; } r = Esys_TR_FromTPMPublic(esys_ctx, tpm2Data->handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &keyHandle); if (r) { ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE); goto error; } r = Esys_ReadPublic(esys_ctx, keyHandle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &outPublic, NULL, NULL); if (r) { ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE); goto error; } /* If the persistent key has the NODA flag set, we check whether it does have an empty authValue. If NODA is not set, then we don't check because that would increment the DA lockout counter */ if ((outPublic->publicArea.objectAttributes & TPMA_OBJECT_NODA) != 0) { ESYS_TR session; TPMT_SYM_DEF sym = {.algorithm = TPM2_ALG_AES, .keyBits = {.aes = 128}, .mode = {.aes = TPM2_ALG_CFB} }; /* Esys_StartAuthSession() and session handling use OpenSSL for random bytes and thus might end up inside this engine again. This becomes a problem if we have no resource manager, i.e. the tpm simulator. */ const RAND_METHOD *rand_save = RAND_get_rand_method(); #if OPENSSL_VERSION_NUMBER < 0x10100000 RAND_set_rand_method(RAND_SSLeay()); #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ RAND_set_rand_method(RAND_OpenSSL()); #endif /* We do the check by starting a bound audit session and executing a very cheap command. */ r = Esys_StartAuthSession(esys_ctx, ESYS_TR_NONE, keyHandle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, NULL, TPM2_SE_HMAC, &sym, TPM2_ALG_SHA256, &session); /* Though this response code is sub-optimal, it's the only way to detect the bug in ESYS. */ if (r == TSS2_ESYS_RC_GENERAL_FAILURE) { DBG("Running tpm2-tss < 2.2 which has a bug here. Requiring auth."); tpm2Data->emptyAuth = 0; goto session_error; } else if (r) { ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE); goto error; } Esys_TRSess_SetAttributes(esys_ctx, session, TPMA_SESSION_ENCRYPT, TPMA_SESSION_ENCRYPT); Esys_TRSess_SetAttributes(esys_ctx, session, TPMA_SESSION_CONTINUESESSION, TPMA_SESSION_CONTINUESESSION); r = Esys_ReadPublic(esys_ctx, keyHandle, session, ESYS_TR_NONE, ESYS_TR_NONE, NULL, NULL, NULL); RAND_set_rand_method(rand_save); /* tpm2-tss < 2.2 has some bugs. (1) it may miscalculate the auth from above leading to a password query in case of empty auth and (2) it may return an error because the object's auth value is "\0". */ if (r == TSS2_RC_SUCCESS) { DBG("Object does not require auth"); tpm2Data->emptyAuth = 1; } else if (r == (TPM2_RC_BAD_AUTH | TPM2_RC_S | TPM2_RC_1)) { DBG("Object does require auth"); tpm2Data->emptyAuth = 0; } else { ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE); goto error; } Esys_FlushContext (esys_ctx, session); } session_error: Esys_TR_Close(esys_ctx, &keyHandle); esys_ctx_free(&esys_ctx); tpm2Data->pub = *outPublic; Esys_Free(outPublic); *tpm2Datap = tpm2Data; return 1; error: if (keyHandle != ESYS_TR_NONE) Esys_TR_Close(esys_ctx, &keyHandle); esys_ctx_free(&esys_ctx); if (tpm2Data) OPENSSL_free(tpm2Data); return 0; } /** Deserialize tpm2data from disk * * Read the tpm2tss key data from a file using PEM encoding. * @param filename The filename to read the data from. * @param tpm2Datap The data after read. * @retval 1 on success * @retval 0 on failure */ int tpm2tss_tpm2data_read(const char *filename, TPM2_DATA **tpm2Datap) { TSS2_RC r; BIO *bio = NULL; TSSPRIVKEY *tpk = NULL; TPM2_DATA *tpm2Data = NULL; char type_oid[64]; BIGNUM *bn_parent; if ((bio = BIO_new_file(filename, "r")) == NULL) { ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ); goto error; } tpk = PEM_read_bio_TSSPRIVKEY(bio, NULL, NULL, NULL); if (!tpk) { ERR(tpm2tss_tpm2data_read, TPM2TSS_R_DATA_CORRUPTED); goto error; } BIO_free(bio); bio = NULL; tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data)); if (tpm2Data == NULL) { ERR(tpm2tss_tpm2data_read, ERR_R_MALLOC_FAILURE); goto error; } memset(tpm2Data, 0, sizeof(*tpm2Data)); tpm2Data->privatetype = KEY_TYPE_BLOB; tpm2Data->emptyAuth = !!tpk->emptyAuth; bn_parent = ASN1_INTEGER_to_BN(tpk->parent, NULL); if (!bn_parent) { goto error; } if (BN_is_negative(bn_parent)) { tpm2Data->parent = ASN1_INTEGER_get(tpk->parent); } else { tpm2Data->parent = BN_get_word(bn_parent); } if (tpm2Data->parent == 0) tpm2Data->parent = TPM2_RH_OWNER; if (!OBJ_obj2txt(type_oid, sizeof(type_oid), tpk->type, 1) || strcmp(type_oid, OID_loadableKey)) { ERR(tpm2tss_tpm2data_read, TPM2TSS_R_CANNOT_MAKE_KEY); goto error; } r = Tss2_MU_TPM2B_PRIVATE_Unmarshal(tpk->privkey->data, tpk->privkey->length, NULL, &tpm2Data->priv); if (r) { ERR(tpm2tss_tpm2data_read, TPM2TSS_R_DATA_CORRUPTED); goto error; } r = Tss2_MU_TPM2B_PUBLIC_Unmarshal(tpk->pubkey->data, tpk->pubkey->length, NULL, &tpm2Data->pub); if (r) { ERR(tpm2tss_tpm2data_read, TPM2TSS_R_DATA_CORRUPTED); goto error; } TSSPRIVKEY_free(tpk); *tpm2Datap = tpm2Data; return 1; error: if (tpm2Data) OPENSSL_free(tpm2Data); if (bio) BIO_free(bio); if (tpk) TSSPRIVKEY_free(tpk); return 0; } static TPM2B_PUBLIC primaryEccTemplate = TPM2B_PUBLIC_PRIMARY_ECC_TEMPLATE; static TPM2B_PUBLIC primaryRsaTemplate = TPM2B_PUBLIC_PRIMARY_RSA_TEMPLATE; static TPM2B_SENSITIVE_CREATE primarySensitive = { .sensitive = { .userAuth = { .size = 0, }, .data = { .size = 0, } } }; static TPM2B_DATA allOutsideInfo = { .size = 0, }; static TPML_PCR_SELECTION allCreationPCR = { .count = 0, }; /** Initialize the ESYS TPM connection and primary/persistent key * * Establish a connection with the TPM using ESYS libraries and create a primary * key under the owner hierarchy or to initialize the ESYS object for a * persistent if provided. * @param esys_ctx The resulting ESYS context. * @param parentHandle The TPM handle of a persistent key or TPM2_RH_OWNER or 0 * @param parent The resulting ESYS_TR handle for the parent key. * @retval TSS2_RC_SUCCESS on success * @retval TSS2_RCs according to the error */ TSS2_RC init_tpm_parent(ESYS_CONTEXT **esys_ctx, TPM2_HANDLE parentHandle, ESYS_TR *parent) { TSS2_RC r; TPM2B_PUBLIC *primaryTemplate = NULL; TPMS_CAPABILITY_DATA *capabilityData = NULL; UINT32 index; *parent = ESYS_TR_NONE; *esys_ctx = NULL; DBG("Establishing connection with TPM.\n"); r = esys_ctx_init(esys_ctx); ERRchktss(init_tpm_parent, r, goto error); if (parentHandle && parentHandle != TPM2_RH_OWNER) { DBG("Connecting to a persistent parent key.\n"); r = Esys_TR_FromTPMPublic(*esys_ctx, parentHandle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, parent); ERRchktss(init_tpm_parent, r, goto error); r = Esys_TR_SetAuth(*esys_ctx, *parent, &parentauth); ERRchktss(init_tpm_parent, r, goto error); return TSS2_RC_SUCCESS; } DBG("Creating primary key under owner.\n"); r = Esys_TR_SetAuth(*esys_ctx, ESYS_TR_RH_OWNER, &ownerauth); ERRchktss(init_tpm_parent, r, goto error); r = Esys_GetCapability (*esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_CAP_ALGS, 0, TPM2_MAX_CAP_ALGS, NULL, &capabilityData); ERRchktss(init_tpm_parent, r, goto error); for (index = 0; index < capabilityData->data.algorithms.count; index++) { if (capabilityData->data.algorithms.algProperties[index].alg == TPM2_ALG_ECC) { primaryTemplate = &primaryEccTemplate; break; } } /* * TPM2_ALG_ECC is *mandatory* for TPM2.0; the above should never * fail. However, *if* such a broken TPM is used then ephemeral * primaries according to the TSS2 PEM file standard can *never* * have worked on that hardware, so it isn't *breaking* anything * for us to unilaterally use an ephemeral RSA parent in this case * instead. * * However, it may not be interoperable to do so, and it isn't a * good idea anyway since RSA keys are *slow* to generate, so * users with a broken TPM like this really *should* have followed * the recommendation to create the RSA primary and store it in * the NVRAM at 0x81000001. And then the TSS2 PEM keys should use * *that* as the parent, not the ephemeral version. In fact, there * is a strong case to be made for defaulting to 0x81000001 if it * exists, *before* (or never) falling back to generating an RSA * key here. */ if (primaryTemplate == NULL) { for (index = 0; index < capabilityData->data.algorithms.count; index++) { if (capabilityData->data.algorithms.algProperties[index].alg == TPM2_ALG_RSA) { primaryTemplate = &primaryRsaTemplate; break; } } } Esys_Free (capabilityData); if (primaryTemplate == NULL) { ERR(init_tpm_parent, TPM2TSS_R_UNKNOWN_ALG); goto error; } r = Esys_CreatePrimary(*esys_ctx, ESYS_TR_RH_OWNER, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &primarySensitive, primaryTemplate, &allOutsideInfo, &allCreationPCR, parent, NULL, NULL, NULL, NULL); if (r == 0x000009a2) { ERR(init_tpm_parent, TPM2TSS_R_OWNER_AUTH_FAILED); goto error; } ERRchktss(init_tpm_parent, r, goto error); return TSS2_RC_SUCCESS; error: if (*parent != ESYS_TR_NONE) Esys_FlushContext(*esys_ctx, *parent); *parent = ESYS_TR_NONE; esys_ctx_free(esys_ctx); return r; } /** Initialize the ESYS TPM connection and load the key * * Establish a connection with the TPM using ESYS libraries, create a primary * key under the owner hierarchy and then load the TPM key and set its auth * value. * @param esys_ctx The ESYS_CONTEXT to be populated. * @param keyHandle The resulting handle for the key key. * @param tpm2Data The key data, owner auth and key auth to be used * @retval TSS2_RC_SUCCESS on success * @retval TSS2_RCs according to the error */ TSS2_RC init_tpm_key (ESYS_CONTEXT **esys_ctx, ESYS_TR *keyHandle, TPM2_DATA *tpm2Data) { TSS2_RC r; ESYS_TR parent = ESYS_TR_NONE; *keyHandle = ESYS_TR_NONE; *esys_ctx = NULL; if (tpm2Data->privatetype == KEY_TYPE_HANDLE) { DBG("Establishing connection with TPM.\n"); r = esys_ctx_init(esys_ctx); ERRchktss(init_tpm_key, r, goto error); r = Esys_TR_FromTPMPublic(*esys_ctx, tpm2Data->handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, keyHandle); ERRchktss(init_tpm_key, r, goto error); } else if (tpm2Data->privatetype == KEY_TYPE_BLOB && tpm2Data->parent != TPM2_RH_OWNER) { r = init_tpm_parent(esys_ctx, tpm2Data->parent, &parent); ERRchktss(init_tpm_key, r, goto error); DBG("Loading key blob.\n"); r = Esys_Load(*esys_ctx, parent, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &tpm2Data->priv, &tpm2Data->pub, keyHandle); Esys_TR_Close(*esys_ctx, &parent); ERRchktss(init_tpm_key, r, goto error); } else if (tpm2Data->privatetype == KEY_TYPE_BLOB) { r = init_tpm_parent(esys_ctx, 0, &parent); ERRchktss(init_tpm_key, r, goto error); DBG("Loading key blob.\n"); r = Esys_Load(*esys_ctx, parent, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &tpm2Data->priv, &tpm2Data->pub, keyHandle); ERRchktss(init_tpm_key, r, goto error); r = Esys_FlushContext(*esys_ctx, parent); ERRchktss(rsa_priv_enc, r, goto error); parent = ESYS_TR_NONE; } else { r = -1; ERR(init_tpm_key, TPM2TSS_R_TPM2DATA_READ_FAILED); goto error; } r = Esys_TR_SetAuth(*esys_ctx, *keyHandle, &tpm2Data->userauth); ERRchktss(init_tpm_key, r, goto error); return TSS2_RC_SUCCESS; error: if (parent != ESYS_TR_NONE) Esys_FlushContext(*esys_ctx, parent); if (*keyHandle != ESYS_TR_NONE) Esys_FlushContext(*esys_ctx, *keyHandle); *keyHandle = ESYS_TR_NONE; esys_ctx_free(esys_ctx); return r; } /** Deserialize a tpm key from disk * * Read a tpm key as marshaled TPM2B_PUBLIC and (encrypted) TPM2B_PRIVATE from * disk and convert them into a TPM2_DATA representation * @param filenamepub The filename to read the public portion from. * @param filenametpm The filename to read the private portion from. * @param parent Handle of the parent key. * @param emptyAuth Whether the object does not require authentication. * @param tpm2Datap The data after read. * @retval 1 on success * @retval 0 on failure */ int tpm2tss_tpm2data_importtpm(const char *filenamepub, const char *filenametpm, TPM2_HANDLE parent, int emptyAuth, TPM2_DATA **tpm2Datap) { TSS2_RC r; BIO *bio; TPM2_DATA *tpm2data; int filepub_size, filepriv_size; uint8_t filepub[sizeof(TPM2B_PUBLIC)]; uint8_t filepriv[sizeof(TPM2B_PRIVATE)]; if ((bio = BIO_new_file(filenamepub, "r")) == NULL) { ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ); return 0; } filepub_size = BIO_read(bio, &filepub[0], sizeof(filepub)); BIO_free(bio); if (filepub_size < 0) { ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ); return 0; } if ((bio = BIO_new_file(filenametpm, "r")) == NULL) { ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ); return 0; } filepriv_size = BIO_read(bio, &filepriv[0], sizeof(filepriv)); BIO_free(bio); if (filepriv_size < 0) { ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ); return 0; } tpm2data = OPENSSL_malloc(sizeof(TPM2_DATA)); if (!tpm2data) return 0; memset(tpm2data, 0, sizeof(*tpm2data)); tpm2data->privatetype = KEY_TYPE_BLOB; tpm2data->parent = parent; tpm2data->emptyAuth = emptyAuth; r = Tss2_MU_TPM2B_PUBLIC_Unmarshal(&filepub[0], filepub_size, NULL, &tpm2data->pub); ERRchktss(tpm2tss_tpm2data_read, r, goto error); r = Tss2_MU_TPM2B_PRIVATE_Unmarshal(&filepriv[0], filepriv_size, NULL, &tpm2data->priv); ERRchktss(tpm2tss_tpm2data_read, r, goto error); *tpm2Datap = tpm2data; return 1; error: OPENSSL_free(tpm2data); return 0; } 0707010000001D000081ED00000000000000000000000164643FF8000019F5000000000000000000000000000000000000004000000000tpm2-tss-engine-1684291576.28be674/src/tpm2-tss-engine-common.h/******************************************************************************* * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG * All rights reserved. * Copyright (c) 2019, Wind River Systems. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of tpm2-tss-engine nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #ifndef TPM2_TSS_ENGINE_COMMON_H #define TPM2_TSS_ENGINE_COMMON_H #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \ && !defined(__STDC_NO_ATOMICS__) # include <stdatomic.h> # define TPM2_TSS_ENGINE_HAVE_C11_ATOMICS typedef _Atomic int T2TE_ATOMIC_INT; #else typedef int T2TE_ATOMIC_INT; #endif #include <tpm2-tss-engine.h> #include <tss2/tss2_mu.h> #include <tss2/tss2_esys.h> #include "tpm2-tss-engine-err.h" #include <openssl/asn1t.h> #include <openssl/asn1.h> #include <openssl/pem.h> extern TPM2B_DIGEST ownerauth; extern TPM2B_DIGEST parentauth; extern char *tcti_nameconf; int init_ecc(ENGINE *e); int init_rand(ENGINE *e); int init_rsa(ENGINE *e); TSS2_RC esys_ctx_init (ESYS_CONTEXT **esys_ctx); TSS2_RC esys_ctx_free (ESYS_CONTEXT **esys_ctx); TSS2_RC init_tpm_parent ( ESYS_CONTEXT **esys_ctx, TPM2_HANDLE parentHandle, ESYS_TR *parent); TSS2_RC init_tpm_key ( ESYS_CONTEXT **esys_ctx, ESYS_TR *keyHandle, TPM2_DATA *tpm2Data); #define ENGINE_HASH_ALG TPM2_ALG_SHA256 #define TPM2B_PUBLIC_PRIMARY_RSA_TEMPLATE { \ .publicArea = { \ .type = TPM2_ALG_RSA, \ .nameAlg = ENGINE_HASH_ALG, \ .objectAttributes = (TPMA_OBJECT_USERWITHAUTH | \ TPMA_OBJECT_RESTRICTED | \ TPMA_OBJECT_DECRYPT | \ TPMA_OBJECT_NODA | \ TPMA_OBJECT_FIXEDTPM | \ TPMA_OBJECT_FIXEDPARENT | \ TPMA_OBJECT_SENSITIVEDATAORIGIN), \ .authPolicy = { \ .size = 0, \ }, \ .parameters.rsaDetail = { \ .symmetric = { \ .algorithm = TPM2_ALG_AES, \ .keyBits.aes = 128, \ .mode.aes = TPM2_ALG_CFB, \ }, \ .scheme = { \ .scheme = TPM2_ALG_NULL, \ .details = {} \ }, \ .keyBits = 2048, \ .exponent = 0,\ }, \ .unique.rsa = { \ .size = 0, \ } \ } \ } /* * The parameters of this key can never be changed because they are * part of the interoperable 'standard' form for TSS2 PEM keys. * Where the parent key is ephemeral and generated on demand, it * has to be generated precisely the *same* every time or it cannot * work. The ECC primary is used for *all* keys regardless of their * type. */ #define TPM2B_PUBLIC_PRIMARY_ECC_TEMPLATE { \ .publicArea = { \ .type = TPM2_ALG_ECC, \ .nameAlg = ENGINE_HASH_ALG, \ .objectAttributes = (TPMA_OBJECT_USERWITHAUTH | \ TPMA_OBJECT_RESTRICTED | \ TPMA_OBJECT_DECRYPT | \ TPMA_OBJECT_NODA | \ TPMA_OBJECT_FIXEDTPM | \ TPMA_OBJECT_FIXEDPARENT | \ TPMA_OBJECT_SENSITIVEDATAORIGIN), \ .authPolicy = { \ .size = 0, \ }, \ .parameters.eccDetail = { \ .symmetric = { \ .algorithm = TPM2_ALG_AES, \ .keyBits.aes = 128, \ .mode.aes = TPM2_ALG_CFB, \ }, \ .scheme = { \ .scheme = TPM2_ALG_NULL, \ .details = {} \ }, \ .curveID = TPM2_ECC_NIST_P256, \ .kdf = { \ .scheme = TPM2_ALG_NULL, \ .details = {} \ }, \ }, \ .unique.ecc = { \ .x.size = 0, \ .y.size = 0 \ } \ } \ } typedef struct { ASN1_OBJECT *type; ASN1_BOOLEAN emptyAuth; ASN1_INTEGER *parent; ASN1_OCTET_STRING *pubkey; ASN1_OCTET_STRING *privkey; } TSSPRIVKEY; DECLARE_ASN1_FUNCTIONS(TSSPRIVKEY); DECLARE_PEM_write_bio(TSSPRIVKEY, TSSPRIVKEY); DECLARE_PEM_read_bio(TSSPRIVKEY, TSSPRIVKEY); #define OID_loadableKey "2.23.133.10.1.3" typedef struct { T2TE_ATOMIC_INT refcount; ESYS_CONTEXT *esys_ctx; ESYS_TR key_handle; int privatetype; } TPM2_SIG_KEY_CTX; typedef struct { TPM2_SIG_KEY_CTX *key; TPM2_ALG_ID hash_alg; ESYS_TR seq_handle; size_t sig_size; } TPM2_SIG_DATA; int digest_update(EVP_MD_CTX *ctx, const void *data, size_t count); int digest_finish(TPM2_SIG_DATA *data, TPM2B_DIGEST **digest, TPMT_TK_HASHCHECK **validation); int digest_sign_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx, TPM2_DATA *tpm2data, size_t sig_size); int digest_sign_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src); void digest_sign_cleanup(EVP_PKEY_CTX *ctx); #endif /* TPM2_TSS_ENGINE_COMMON_H */ 0707010000001E000081A400000000000000000000000164643FF800002656000000000000000000000000000000000000004500000000tpm2-tss-engine-1684291576.28be674/src/tpm2-tss-engine-digest-sign.c/******************************************************************************* * Copyright 2021, Graphiant, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of tpm2-tss-engine nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #include <string.h> #include <openssl/evp.h> #include <tss2/tss2_esys.h> #include "tpm2-tss-engine-common.h" #ifndef TPM2_TSS_ENGINE_HAVE_C11_ATOMICS /* fall back to using GCC/clang atomic builtins */ # define atomic_fetch_add(PTR, VAL) \ __atomic_fetch_add((PTR), (VAL), __ATOMIC_SEQ_CST) #define atomic_fetch_sub(PTR, VAL) \ __atomic_fetch_sub ((PTR), (VAL), __ATOMIC_SEQ_CST) #endif /* TPM2_TSS_ENGINE_HAVE_C11_ATOMICS */ /** * Initialise a digest operation for digest and sign. * * @param ctx OpenSSL message digest context * @param data Digest and sign data * @retval 1 on success * @retval 0 on failure */ static int digest_init(EVP_MD_CTX *ctx, TPM2_SIG_DATA *data) { TPM2B_AUTH null_auth = { .size = 0 }; const EVP_MD *md; TSS2_RC r; md = EVP_MD_CTX_md(ctx); if (!md) { ERR(digest_init, TPM2TSS_R_GENERAL_FAILURE); return 0; } switch (EVP_MD_type(md)) { case NID_sha1: data->hash_alg = TPM2_ALG_SHA1; break; case NID_sha256: data->hash_alg = TPM2_ALG_SHA256; break; case NID_sha384: data->hash_alg = TPM2_ALG_SHA384; break; case NID_sha512: data->hash_alg = TPM2_ALG_SHA512; break; default: ERR(digest_init, TPM2TSS_R_UNKNOWN_ALG); return 0; } r = Esys_HashSequenceStart(data->key->esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &null_auth, data->hash_alg, &data->seq_handle); ERRchktss(digest_init, r, return 0); return 1; } /** * Update a digest with more data * * @param ctx OpenSSL message digest context * @param data Data to add to digest * @param count Length of data to add * @retval 1 on success * @retval 0 on failure */ int digest_update(EVP_MD_CTX *ctx, const void *data, size_t count) { EVP_PKEY_CTX *pctx = EVP_MD_CTX_pkey_ctx(ctx); TPM2_SIG_DATA *sig_data = EVP_PKEY_CTX_get_app_data(pctx); const uint8_t *current_data = data; TSS2_RC r; DBG("digest_update %p %p\n", pctx, ctx); while (count > 0) { TPM2B_MAX_BUFFER digest_data = { .size = count }; if (digest_data.size > sizeof(digest_data.buffer)) digest_data.size = sizeof(digest_data.buffer); memcpy(&digest_data.buffer[0], current_data, digest_data.size); current_data += digest_data.size; count -= digest_data.size; r = Esys_SequenceUpdate(sig_data->key->esys_ctx, sig_data->seq_handle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &digest_data); ERRchktss(digest_update, r, return 0); } return 1; } /** * Finish a digest operation for digest and sign * * @param data Digest and sign data * @param digest Digest calculated by TPM * @param validation Validation ticket for the digest calculated by TPM * @retval 1 on success * @retval 0 on failure */ int digest_finish(TPM2_SIG_DATA *data, TPM2B_DIGEST **digest, TPMT_TK_HASHCHECK **validation) { TSS2_RC r; r = Esys_SequenceComplete(data->key->esys_ctx, data->seq_handle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, NULL, ESYS_TR_RH_OWNER, digest, validation); ERRchktss(digest_finish, r, return 0); /* Esys_SequenceComplete consumes the handle */ data->seq_handle = ESYS_TR_NONE; return 1; } /** * Initialise a digest and sign operation * * @param ctx OpenSSL pkey context * @param mctx OpenSSL message digest context * @param tpm2data TPM data for the key to use * @param sig_size Size of the signature data * @retval 1 on success * @retval 0 on failure */ int digest_sign_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx, TPM2_DATA *tpm2data, size_t sig_size) { TSS2_RC r; if (!tpm2data) /* non-TPM key - nothing to do */ return 1; TPM2_SIG_DATA *data = OPENSSL_malloc(sizeof(*data)); if (!data) { ERR(digest_sign_init, ERR_R_MALLOC_FAILURE); return 0; } data->seq_handle = ESYS_TR_NONE; data->sig_size = sig_size; data->key = OPENSSL_malloc(sizeof(*data->key)); if (!data->key) { ERR(digest_sign_init, ERR_R_MALLOC_FAILURE); goto error; } data->key->refcount = 1; r = init_tpm_key(&data->key->esys_ctx, &data->key->key_handle, tpm2data); ERRchktss(digest_sign_init, r, goto error); data->key->privatetype = tpm2data->privatetype; EVP_PKEY_CTX_set_app_data(ctx, data); /* * Override the update function so that the TPM performs the * digest, which is required for restricted keys - the TPM will * reject a null validation ticket in this case for the signing * operation. */ EVP_MD_CTX_set_update_fn(mctx, digest_update); if (!digest_init(mctx, data)) goto error; return 1; error: if (data->key) { if (data->key->key_handle != ESYS_TR_NONE) { if (data->key->privatetype == KEY_TYPE_HANDLE) { Esys_TR_Close(data->key->esys_ctx, &data->key->key_handle); } else { Esys_FlushContext(data->key->esys_ctx, data->key->key_handle); } } if (data->key->esys_ctx) esys_ctx_free(&data->key->esys_ctx); OPENSSL_free(data->key); } OPENSSL_free(data); return 0; } /** * Copy digest and sign context * * @param dst Destination OpenSSL pkey context * @param src Source OpenSSL pkey context * @retval 1 on success * @retval 0 on failure */ int digest_sign_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { TPM2_SIG_DATA *src_sig_data = EVP_PKEY_CTX_get_app_data(src); TPMS_CONTEXT *context = NULL; TPM2_SIG_DATA *dst_sig_data = NULL; TSS2_RC r; if (src_sig_data) { dst_sig_data = OPENSSL_malloc(sizeof(*dst_sig_data)); if (!dst_sig_data) { ERR(digest_sign_copy, ERR_R_MALLOC_FAILURE); return 0; } dst_sig_data->hash_alg = src_sig_data->hash_alg; dst_sig_data->sig_size = src_sig_data->sig_size; if (src_sig_data->seq_handle != ESYS_TR_NONE) { /* duplicate sequence handle */ r = Esys_ContextSave(src_sig_data->key->esys_ctx, src_sig_data->seq_handle, &context); ERRchktss(digest_sign_copy, r, goto error); dst_sig_data->seq_handle = ESYS_TR_NONE; r = Esys_ContextLoad(src_sig_data->key->esys_ctx, context, &dst_sig_data->seq_handle); ERRchktss(digest_sign_copy, r, goto error); } dst_sig_data->key = src_sig_data->key; atomic_fetch_add(&dst_sig_data->key->refcount, 1); EVP_PKEY_CTX_set_app_data(dst, dst_sig_data); } Esys_Free(context); return 1; error: Esys_Free(context); OPENSSL_free(dst_sig_data); return 0; } /** * Clean up digest and sign context * * @param ctx OpenSSL pkey context * @retval 1 on success * @retval 0 on failure */ void digest_sign_cleanup(EVP_PKEY_CTX *ctx) { TPM2_SIG_DATA *sig_data = EVP_PKEY_CTX_get_app_data(ctx); if (sig_data) { if (sig_data->seq_handle != ESYS_TR_NONE) Esys_FlushContext(sig_data->key->esys_ctx, sig_data->seq_handle); if (atomic_fetch_sub(&sig_data->key->refcount, 1) == 1) { if (sig_data->key->key_handle != ESYS_TR_NONE) { if (sig_data->key->privatetype == KEY_TYPE_HANDLE) { Esys_TR_Close(sig_data->key->esys_ctx, &sig_data->key->key_handle); } else { Esys_FlushContext(sig_data->key->esys_ctx, sig_data->key->key_handle); } } esys_ctx_free(&sig_data->key->esys_ctx); OPENSSL_free(sig_data->key); } OPENSSL_free(sig_data); EVP_PKEY_CTX_set_app_data(ctx, NULL); } } 0707010000001F000081A400000000000000000000000164643FF800006646000000000000000000000000000000000000003D00000000tpm2-tss-engine-1684291576.28be674/src/tpm2-tss-engine-ecc.c/******************************************************************************* * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of tpm2-tss-engine nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #include <string.h> #include <openssl/engine.h> #include <openssl/ec.h> #include <openssl/ecdsa.h> #include <tss2/tss2_mu.h> #include <tss2/tss2_esys.h> #include "tpm2-tss-engine.h" #include "tpm2-tss-engine-common.h" static int ec_key_app_data = -1; #if OPENSSL_VERSION_NUMBER < 0x10100000 const ECDSA_METHOD *ecc_method_default = NULL; ECDSA_METHOD *ecc_methods = NULL; #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ const EC_KEY_METHOD *ecc_method_default = NULL; EC_KEY_METHOD *ecc_methods = NULL; #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ #ifdef HAVE_OPENSSL_DIGEST_SIGN static int (*ecdsa_pkey_orig_copy)(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src); static void (*ecdsa_pkey_orig_cleanup)(EVP_PKEY_CTX *ctx); #endif /* HAVE_OPENSSL_DIGEST_SIGN */ static TPM2B_DATA allOutsideInfo = { .size = 0, }; static TPML_PCR_SELECTION allCreationPCR = { .count = 0, }; static TPM2B_PUBLIC keyEcTemplate = { .publicArea = { .type = TPM2_ALG_ECC, .nameAlg = ENGINE_HASH_ALG, .objectAttributes = (TPMA_OBJECT_USERWITHAUTH | TPMA_OBJECT_SIGN_ENCRYPT | TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT | TPMA_OBJECT_SENSITIVEDATAORIGIN | TPMA_OBJECT_NODA), .parameters.eccDetail = { .curveID = 0, /* To be filled out later */ .symmetric = { .algorithm = TPM2_ALG_NULL, .keyBits.aes = 0, .mode.aes = 0, }, .scheme = { .scheme = TPM2_ALG_NULL, .details = {} }, .kdf = { .scheme = TPM2_ALG_NULL, .details = {} }, }, .unique.ecc = { .x.size = 0, .y.size = 0 } } }; #if OPENSSL_VERSION_NUMBER < 0x10100000 static int EC_GROUP_order_bits(const EC_GROUP *group) { if (!group) return 0; BIGNUM *order = BN_new(); if (order == NULL) { ERR_clear_error(); return 0; } int ret = 0; if (!EC_GROUP_get_order(group, order, NULL)) { ERR_clear_error(); BN_free(order); return 0; } ret = BN_num_bits(order); BN_free(order); return ret; } #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ /** * Initialize a TPM2B_ECC_POINT from an OpenSSL EC_POINT. * * @param point Pointer to output tpm point * @param pub_key OpenSSL public key to convert * @param group Curve group * @retval 0 on failure */ static int init_tpm_public_point(TPM2B_ECC_POINT *point, const EC_POINT *ec_point, const EC_GROUP *ec_group) { unsigned char buffer[1 + sizeof(point->point.x.buffer) + sizeof(point->point.y.buffer)] = {0}; BN_CTX *ctx = BN_CTX_new(); if (!ctx) return 0; BN_CTX_start(ctx); size_t len = 0; // first, check for actual buffer size required if ((len = EC_POINT_point2oct(ec_group, ec_point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, ctx)) <= sizeof(buffer)) { len = EC_POINT_point2oct(ec_group, ec_point, POINT_CONVERSION_UNCOMPRESSED, buffer, sizeof(buffer), ctx); } BN_CTX_end(ctx); BN_CTX_free(ctx); if (len == 0 || len > sizeof(buffer)) return 0; len = (len - 1) / 2; point->point.x.size = len; point->point.y.size = len; memcpy(point->point.x.buffer, &buffer[1], len); memcpy(point->point.y.buffer, &buffer[1 + len], len); return 1; } /** * Generate a shared secret using a TPM key * * @param psec Pointer to output buffer holding shared secret * @param pseclen Size of the psec buffer * @param pub_key The peer's public key * @param ecdh The ECC key object for the host private key * @retval 0 on failure */ static int ecdh_compute_key(unsigned char **psec, size_t *pseclen, const EC_POINT *pub_key, const EC_KEY *eckey) { /* * If this is not a TPM2 key, bail out since fall through to software * functions requires a non-const EC_KEY, yet the ECDH prototype only * provides it as const. */ TPM2_DATA *tpm2Data = tpm2tss_ecc_getappdata(eckey); if (tpm2Data == NULL) return 0; TPM2B_ECC_POINT inPoint; TPM2B_ECC_POINT *outPoint = NULL; const EC_GROUP *group = EC_KEY_get0_group(eckey); int ret = init_tpm_public_point(&inPoint, pub_key, group); if (!ret) return 0; ESYS_CONTEXT *esys_ctx = NULL; ESYS_TR keyHandle = ESYS_TR_NONE; TSS2_RC r = init_tpm_key(&esys_ctx, &keyHandle, tpm2Data); ERRchktss(ecdh_compute_key, r, goto error); r = Esys_ECDH_ZGen(esys_ctx, keyHandle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &inPoint, &outPoint); ERRchktss(ecdh_compute_key, r, goto error); *pseclen = outPoint->point.x.size; *psec = OPENSSL_malloc(*pseclen); if (!*psec) goto error; memcpy(*psec, outPoint->point.x.buffer, *pseclen); ret = 1; goto out; error: ret = 0; out: if (keyHandle != ESYS_TR_NONE) { if (tpm2Data->privatetype == KEY_TYPE_HANDLE) { Esys_TR_Close(esys_ctx, &keyHandle); } else { Esys_FlushContext(esys_ctx, keyHandle); } } Esys_Free(outPoint); esys_ctx_free(&esys_ctx); return ret; } #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ static ECDSA_SIG * ecdsa_sign(ESYS_CONTEXT *esys_ctx, ESYS_TR key_handle, TPM2B_DIGEST *digest, TPMT_TK_HASHCHECK *validation, TPM2_ALG_ID hash_alg) { TPMT_SIG_SCHEME inScheme = { .scheme = TPM2_ALG_ECDSA, .details.ecdsa.hashAlg = hash_alg, }; BIGNUM *bns = NULL, *bnr = NULL; ECDSA_SIG *ret = NULL; TPMT_SIGNATURE *sig = NULL; TSS2_RC r; r = Esys_Sign(esys_ctx, key_handle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, digest, &inScheme, validation, &sig); ERRchktss(ecdsa_sign, r, goto error); ret = ECDSA_SIG_new(); if (ret == NULL) { ERR(ecdsa_sign, ERR_R_MALLOC_FAILURE); goto error; } bns = BN_bin2bn(&sig->signature.ecdsa.signatureS.buffer[0], sig->signature.ecdsa.signatureS.size, NULL); bnr = BN_bin2bn(&sig->signature.ecdsa.signatureR.buffer[0], sig->signature.ecdsa.signatureR.size, NULL); if (!bns || !bnr) { ERR(ecdsa_sign, ERR_R_MALLOC_FAILURE); goto error; } #if OPENSSL_VERSION_NUMBER < 0x10100000 ret->s = bns; ret->r = bnr; #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ ECDSA_SIG_set0(ret, bnr, bns); #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ goto out; error: if (bns) BN_free(bns); if (bnr) BN_free(bnr); if (ret) ECDSA_SIG_free(ret); ret = NULL; out: Esys_Free(sig); return ret; } /** Sign data using a TPM key * * This function performs the sign function using the private key in ECDSA. * This operation is usually used to perform signature and authentication * operations. * @param dgst The data to be signed. * @param dgst_len Length of the from buffer. * @param inv Ignored * @param rp Ignored * @param eckey The ECC key object. * @retval 0 on failure * @retval size Size of the returned signature */ static ECDSA_SIG * ecdsa_ec_key_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv, const BIGNUM *rp, EC_KEY *eckey) { ECDSA_SIG *ret = NULL; TPM2_DATA *tpm2Data = tpm2tss_ecc_getappdata(eckey); TPM2_ALG_ID hash_alg; /* If this is not a TPM2 key, fall through to software functions */ if (tpm2Data == NULL) { #if OPENSSL_VERSION_NUMBER < 0x10100000 ECDSA_set_method(eckey, ecc_method_default); ret = ECDSA_do_sign_ex(dgst, dgst_len, inv, rp, eckey); ECDSA_set_method(eckey, ecc_methods); return ret; #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ EC_KEY_set_method(eckey, ecc_method_default); ret = ECDSA_do_sign_ex(dgst, dgst_len, inv, rp, eckey); EC_KEY_set_method(eckey, ecc_methods); return ret; #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ } DBG("ecdsa_sign called for input data(size=%i):\n", dgst_len); DBGBUF(dgst, dgst_len); TSS2_RC r; ESYS_CONTEXT *esys_ctx = NULL; ESYS_TR keyHandle = ESYS_TR_NONE; TPMT_TK_HASHCHECK validation = { .tag = TPM2_ST_HASHCHECK, .hierarchy = TPM2_RH_NULL, .digest.size = 0 }; /* * ECDSA signatures truncate the incoming hash to fit the curve, * and the signature mechanism is the same regardless of the * hash being used. * * The TPM bizarrely wants to be told the hash algorithm, and * either it or the TSS will validate that the digest length * matches the hash that it's told, despite it having no business * caring about such things. * * So, we can truncate the digest any pretend it's any smaller * digest that the TPM actually does support, as long as that * digest is larger than the size of the curve. */ int curve_len = (EC_GROUP_order_bits(EC_KEY_get0_group(eckey)) + 7) / 8; /* If we couldn't work it out, don't truncate */ if (!curve_len) curve_len = dgst_len; if (dgst_len == SHA_DIGEST_LENGTH || (curve_len <= SHA_DIGEST_LENGTH && dgst_len > SHA_DIGEST_LENGTH)) { hash_alg = TPM2_ALG_SHA1; dgst_len = SHA_DIGEST_LENGTH; } else if (dgst_len == SHA256_DIGEST_LENGTH || (curve_len <= SHA256_DIGEST_LENGTH && dgst_len > SHA256_DIGEST_LENGTH)) { hash_alg = TPM2_ALG_SHA256; dgst_len = SHA256_DIGEST_LENGTH; } else if (dgst_len == SHA384_DIGEST_LENGTH || (curve_len <= SHA384_DIGEST_LENGTH && dgst_len > SHA384_DIGEST_LENGTH)) { hash_alg = TPM2_ALG_SHA384; dgst_len = SHA384_DIGEST_LENGTH; } else if (dgst_len == SHA512_DIGEST_LENGTH || (curve_len <= SHA512_DIGEST_LENGTH && dgst_len > SHA512_DIGEST_LENGTH)) { hash_alg = TPM2_ALG_SHA512; dgst_len = SHA512_DIGEST_LENGTH; } else { ERR(ecdsa_sign, TPM2TSS_R_PADDING_UNKNOWN); goto error; } TPM2B_DIGEST digest = { .size = dgst_len }; if (digest.size > sizeof(digest.buffer)) { ERR(ecdsa_sign, TPM2TSS_R_DIGEST_TOO_LARGE); goto error; } memcpy(&digest.buffer[0], dgst, digest.size); r = init_tpm_key(&esys_ctx, &keyHandle, tpm2Data); ERRchktss(ecdsa_sign, r, goto error); ret = ecdsa_sign(esys_ctx, keyHandle, &digest, &validation, hash_alg); goto out; error: r = -1; out: if (keyHandle != ESYS_TR_NONE) { if (tpm2Data->privatetype == KEY_TYPE_HANDLE) { Esys_TR_Close(esys_ctx, &keyHandle); } else { Esys_FlushContext(esys_ctx, keyHandle); } } esys_ctx_free(&esys_ctx); return (r == TSS2_RC_SUCCESS) ? ret : NULL; } #ifdef HAVE_OPENSSL_DIGEST_SIGN static int ecdsa_pkey_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { if (ecdsa_pkey_orig_copy && !ecdsa_pkey_orig_copy(dst, src)) return 0; return digest_sign_copy(dst, src); } static void ecdsa_pkey_cleanup(EVP_PKEY_CTX *ctx) { digest_sign_cleanup(ctx); if (ecdsa_pkey_orig_cleanup) ecdsa_pkey_orig_cleanup(ctx); } /* called for digest & sign init, after message digest algorithm set */ static int ecdsa_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) { EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx); EC_KEY *eckey = EVP_PKEY_get0_EC_KEY(pkey); TPM2_DATA *tpm2data = tpm2tss_ecc_getappdata(eckey); DBG("ecdsa_digest_custom %p %p\n", ctx, mctx); return digest_sign_init(ctx, mctx, tpm2data, ECDSA_size(eckey)); } static int ecdsa_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, EVP_MD_CTX *mctx) { TPM2_SIG_DATA *sig_data = EVP_PKEY_CTX_get_app_data(ctx); TSS2_RC r = TSS2_RC_SUCCESS; TPMT_TK_HASHCHECK *validation_ptr = NULL; TPM2B_DIGEST *digest_ptr = NULL; ECDSA_SIG *ecdsa_s = NULL; DBG("ecdsa_signctx %p %p sig_data %p\n", ctx, mctx, sig_data); if (!sig) { /* caller just wants to know the size */ *siglen = sig_data->sig_size; return 1; } if (!sig_data) { /* handle non-TPM key */ unsigned char md[EVP_MAX_MD_SIZE]; unsigned int md_len = 0; if (!EVP_DigestFinal_ex(mctx, md, &md_len)) return 0; if (EVP_PKEY_sign(ctx, sig, siglen, md, md_len) <= 0) return 0; return 1; } if (!digest_finish(sig_data, &digest_ptr, &validation_ptr)) return 0; ecdsa_s = ecdsa_sign(sig_data->key->esys_ctx, sig_data->key->key_handle, digest_ptr, validation_ptr, sig_data->hash_alg); if (!ecdsa_s) goto error; *siglen = i2d_ECDSA_SIG(ecdsa_s, &sig); r = 1; goto out; error: r = 0; out: ECDSA_SIG_free(ecdsa_s); Esys_Free(digest_ptr); Esys_Free(validation_ptr); return r; } #endif /* HAVE_OPENSSL_DIGEST_SIGN */ /** Helper to populate the ECC key object. * * In order to use an ECC key object in a typical manner, all fields of the * OpenSSL's corresponding object bust be filled. This function fills the public * values correctly. * @param key The key object to fill. * @retval 0 on failure * @retval 1 on success */ static int populate_ecc(EC_KEY *key) { EC_GROUP *ecgroup = NULL; int nid; BIGNUM *x = NULL, *y = NULL; TPM2_DATA *tpm2Data = tpm2tss_ecc_getappdata(key); if (tpm2Data == NULL) return 0; switch (tpm2Data->pub.publicArea.parameters.eccDetail.curveID) { case TPM2_ECC_NIST_P256: nid = EC_curve_nist2nid("P-256"); break; case TPM2_ECC_NIST_P384: nid = EC_curve_nist2nid("P-384"); break; default: nid = -1; } if (nid < 0) { ERR(populate_ecc, TPM2TSS_R_UNKNOWN_CURVE); return 0; } ecgroup = EC_GROUP_new_by_curve_name(nid); if (ecgroup == NULL) { ERR(populate_ecc, TPM2TSS_R_UNKNOWN_CURVE); return 0; } if (!EC_KEY_set_group(key, ecgroup)) { ERR(populate_ecc, TPM2TSS_R_GENERAL_FAILURE); EC_GROUP_free(ecgroup); return 0; } EC_KEY_set_asn1_flag(key, OPENSSL_EC_NAMED_CURVE); EC_GROUP_free(ecgroup); x = BN_bin2bn(tpm2Data->pub.publicArea.unique.ecc.x.buffer, tpm2Data->pub.publicArea.unique.ecc.x.size, NULL); y = BN_bin2bn(tpm2Data->pub.publicArea.unique.ecc.y.buffer, tpm2Data->pub.publicArea.unique.ecc.y.size, NULL); if (!x || !y) { ERR(populate_ecc, ERR_R_MALLOC_FAILURE); return 0; } if (!EC_KEY_set_public_key_affine_coordinates(key, x, y)) { ERR(populate_ecc, TPM2TSS_R_GENERAL_FAILURE); BN_free(y); BN_free(x); return 0; } BN_free(y); BN_free(x); return 1; } /** Helper to load an ECC key from a tpm2Data * * This function creates a key object given a TPM2_DATA object. The resulting * key object can then be used for signing with the tpm2tss engine. Ownership * of the TPM2_DATA object is taken on success. * @param tpm2Data The key data to use. Must have been allocated using * OPENSSL_malloc. * @retval key The key object * @retval NULL on failure. */ EVP_PKEY * tpm2tss_ecc_makekey(TPM2_DATA *tpm2Data) { DBG("Creating ECC key object.\n"); EVP_PKEY *pkey; EC_KEY *eckey; /* create the new objects to return */ if ((pkey = EVP_PKEY_new()) == NULL) { ERR(tpm2tss_ecc_makekey, ERR_R_MALLOC_FAILURE); return NULL; } if ((eckey = EC_KEY_new()) == NULL) { ERR(tpm2tss_ecc_makekey, ERR_R_MALLOC_FAILURE); EVP_PKEY_free(pkey); return NULL; } #if OPENSSL_VERSION_NUMBER < 0x10100000 if (!ECDSA_set_method(eckey, ecc_methods)) { #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ if (!EC_KEY_set_method(eckey, ecc_methods)) { #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ ERR(tpm2tss_ecc_makekey, TPM2TSS_R_GENERAL_FAILURE); EC_KEY_free(eckey); goto error; } if (!EVP_PKEY_assign_EC_KEY(pkey, eckey)) { ERR(tpm2tss_ecc_makekey, TPM2TSS_R_GENERAL_FAILURE); EC_KEY_free(eckey); goto error; } if (!tpm2tss_ecc_setappdata(eckey, tpm2Data)) { ERR(tpm2tss_ecc_makekey, TPM2TSS_R_GENERAL_FAILURE); goto error; } if (!populate_ecc(eckey)) goto error; DBG("Created ECC key object.\n"); return pkey; error: EVP_PKEY_free(pkey); return NULL; } /** Retrieve app data * * Since the ECC api (opposed to the RSA api) does not provide a standardized * way to retrieve app data between the library and an application, this helper * is defined * @param key The key object * @retval tpm2Data The corresponding TPM data * @retval NULL on failure. */ TPM2_DATA * #if OPENSSL_VERSION_NUMBER < 0x10100000 tpm2tss_ecc_getappdata(EC_KEY *key) #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ tpm2tss_ecc_getappdata(const EC_KEY *key) #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ { if (ec_key_app_data == -1) { DBG("Module uninitialized\n"); return NULL; } #if OPENSSL_VERSION_NUMBER < 0x10100000 return ECDSA_get_ex_data(key, ec_key_app_data); #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ return EC_KEY_get_ex_data(key, ec_key_app_data); #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ } /** Set app data * * Since the ECC api (opposed to the RSA api) does not provide a standardized * way to set app data between the library and an application, this helper * is defined * @param key The key object * @param tpm2Data The corresponding TPM data * @retval 1 on success * @retval 0 on failure */ int tpm2tss_ecc_setappdata(EC_KEY *key, TPM2_DATA *tpm2Data) { if (ec_key_app_data == -1) { DBG("Module uninitialized\n"); return 0; } #if OPENSSL_VERSION_NUMBER < 0x10100000 return ECDSA_set_ex_data(key, ec_key_app_data, tpm2Data); #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ return EC_KEY_set_ex_data(key, ec_key_app_data, tpm2Data); #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ } static void free_ecc_appdata(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp) { TPM2_DATA *tpm2Data = ptr; (void)parent; (void)ad; (void)idx; (void)argl; (void)argp; if (!ptr) return; OPENSSL_free(tpm2Data); } /** Generate a tpm2tss ecc key object. * * This function creates a new TPM ECC key. The TPM data is stored inside the * object*s app data and can be retrieved using tpm2tss_ecc_getappdata(). * @param key The key object for the TPM ECC key to be created * @param curve The curve to be used for the key * @param password The Password to be set for the new key * @retval 1 on success * @retval 0 on failure */ int tpm2tss_ecc_genkey(EC_KEY *key, TPMI_ECC_CURVE curve, const char *password, TPM2_HANDLE parentHandle) { DBG("GenKey for ecdsa.\n"); TSS2_RC r; ESYS_CONTEXT *esys_ctx = NULL; ESYS_TR parent = ESYS_TR_NONE; TPM2B_PUBLIC *keyPublic = NULL; TPM2B_PRIVATE *keyPrivate = NULL; TPM2_DATA *tpm2Data = NULL; TPM2B_PUBLIC inPublic = keyEcTemplate; TPM2B_SENSITIVE_CREATE inSensitive = { .sensitive = { .userAuth = { .size = 0, }, .data = { .size = 0, } } }; tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data)); if (tpm2Data == NULL) { ERR(tpm2tss_ecc_genkey, ERR_R_MALLOC_FAILURE); goto error; } memset(tpm2Data, 0, sizeof(*tpm2Data)); inPublic.publicArea.parameters.eccDetail.curveID = curve; if (password) { DBG("Setting a password for the created key.\n"); if (strlen(password) > sizeof(tpm2Data->userauth.buffer) - 1 || strlen(password) > sizeof(inSensitive.sensitive.userAuth.buffer) - 1) { goto error; } tpm2Data->userauth.size = strlen(password); memcpy(&tpm2Data->userauth.buffer[0], password, tpm2Data->userauth.size); inSensitive.sensitive.userAuth.size = strlen(password); memcpy(&inSensitive.sensitive.userAuth.buffer[0], password, strlen(password)); } else tpm2Data->emptyAuth = 1; r = init_tpm_parent(&esys_ctx, parentHandle, &parent); ERRchktss(tpm2tss_ecc_genkey, r, goto error); tpm2Data->parent = parentHandle; DBG("Generating the ECC key inside the TPM.\n"); r = Esys_Create(esys_ctx, parent, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &inSensitive, &inPublic, &allOutsideInfo, &allCreationPCR, &keyPrivate, &keyPublic, NULL, NULL, NULL); ERRchktss(tpm2tss_ecc_genkey, r, goto error); DBG("Generated the ECC key inside the TPM.\n"); tpm2Data->pub = *keyPublic; tpm2Data->priv = *keyPrivate; if (!tpm2tss_ecc_setappdata(key, tpm2Data)) { ERR(tpm2tss_ecc_genkey, TPM2TSS_R_GENERAL_FAILURE); goto error; } if (!populate_ecc(key)) { goto error; } goto end; error: r = -1; tpm2tss_ecc_setappdata(key, NULL); if (tpm2Data) OPENSSL_free(tpm2Data); end: Esys_Free(keyPrivate); Esys_Free(keyPublic); if (parent != ESYS_TR_NONE && !parentHandle) Esys_FlushContext(esys_ctx, parent); esys_ctx_free(&esys_ctx); return (r == TSS2_RC_SUCCESS); } /** Initialize the tpm2tss engine's ecc submodule * * Initialize the tpm2tss engine's submodule by setting function pointer. * @param e The engine context. * @retval 1 on success * @retval 0 on failure */ int init_ecc(ENGINE *e) { (void)(e); #if OPENSSL_VERSION_NUMBER < 0x10100000 ecc_method_default = ECDSA_OpenSSL(); if (ecc_method_default == NULL) return 0; ecc_methods = ECDSA_METHOD_new(ecc_method_default); if (ecc_methods == NULL) return 0; ECDSA_METHOD_set_sign(ecc_methods, ecdsa_ec_key_sign); if (ec_key_app_data == -1) ec_key_app_data = ECDSA_get_ex_new_index(0, NULL, NULL, NULL, free_ecc_appdata); #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ ecc_method_default = EC_KEY_OpenSSL(); if (ecc_method_default == NULL) return 0; ecc_methods = EC_KEY_METHOD_new(ecc_method_default); if (ecc_methods == NULL) return 0; int (*orig_sign) (int, const unsigned char *, int, unsigned char *, unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL; EC_KEY_METHOD_get_sign(ecc_methods, &orig_sign, NULL, NULL); EC_KEY_METHOD_set_sign(ecc_methods, orig_sign, NULL, ecdsa_ec_key_sign); EC_KEY_METHOD_set_compute_key(ecc_methods, ecdh_compute_key); if (ec_key_app_data == -1) ec_key_app_data = EC_KEY_get_ex_new_index(0, NULL, NULL, NULL, free_ecc_appdata); #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ #if HAVE_OPENSSL_DIGEST_SIGN /* digest and sign support */ EVP_PKEY_METHOD *pkey_ecc_methods; pkey_ecc_methods = EVP_PKEY_meth_new(EVP_PKEY_EC, 0); if (pkey_ecc_methods == NULL) return 0; const EVP_PKEY_METHOD *pkey_orig_ecc_methods = EVP_PKEY_meth_find(EVP_PKEY_EC); if (pkey_orig_ecc_methods == NULL) return 0; EVP_PKEY_meth_copy(pkey_ecc_methods, pkey_orig_ecc_methods); /* * save originals since we only override some of the pkey * functionality, rather than reimplementing all of it */ EVP_PKEY_meth_get_copy(pkey_ecc_methods, &ecdsa_pkey_orig_copy); EVP_PKEY_meth_get_cleanup(pkey_ecc_methods, &ecdsa_pkey_orig_cleanup); EVP_PKEY_meth_set_copy(pkey_ecc_methods, ecdsa_pkey_copy); EVP_PKEY_meth_set_cleanup(pkey_ecc_methods, ecdsa_pkey_cleanup); EVP_PKEY_meth_set_signctx(pkey_ecc_methods, NULL, ecdsa_signctx); EVP_PKEY_meth_set_digest_custom(pkey_ecc_methods, ecdsa_digest_custom); EVP_PKEY_meth_add0(pkey_ecc_methods); #endif /* HAVE_OPENSSL_DIGEST_SIGN */ return 1; } 07070100000020000081A400000000000000000000000164643FF800001A89000000000000000000000000000000000000003D00000000tpm2-tss-engine-1684291576.28be674/src/tpm2-tss-engine-err.c/******************************************************************************* * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of tpm2-tss-engine nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #include <openssl/err.h> #include "tpm2-tss-engine-err.h" #define TPM2TSS_LIB_NAME "tpm2-tss-engine" #define xstr(s) str(s) #define str(s) #s #define ERR_F(f) { ERR_PACK(0, TPM2TSS_F_ ## f, 0), xstr(f) } #define ERR_R(r, s) { ERR_PACK(0, 0, r), xstr(s) } #ifndef OPENSSL_NO_ERR static ERR_STRING_DATA TPM2TSS_f[] = { /* tpm2-tss-engine.c */ ERR_F(loadkey), ERR_F(init_engine), ERR_F(get_auth), ERR_F(engine_ctrl), /* tpm2-tss-engine-common.c */ ERR_F(tpm2tss_tpm2data_write), ERR_F(tpm2tss_tpm2data_read), ERR_F(tpm2tss_tpm2data_readtpm), ERR_F(init_tpm_parent), ERR_F(init_tpm_key), ERR_F(esys_ctx_init), ERR_F(esys_ctx_free), /* tpm2-tss-engine-ecc.c */ ERR_F(ecdsa_sign), ERR_F(populate_ecc), ERR_F(tpm2tss_ecc_genkey), ERR_F(tpm2tss_ecc_makekey), /* tpm2-tss-engine-rand.c */ ERR_F(rand_bytes), ERR_F(rand_seed), /* tpm2-tss-engine-rsa.c */ ERR_F(rsa_priv_enc), ERR_F(rsa_priv_dec), ERR_F(tpm2tss_rsa_genkey), ERR_F(populate_rsa), {0, NULL} }; static ERR_STRING_DATA TPM2TSS_r[] = { ERR_R(TPM2TSS_R_TPM2DATA_READ_FAILED, Failed to read TPM2 data), ERR_R(TPM2TSS_R_UNKNOWN_ALG, The algorithm is unknown (neither RSA, ECDSA)), ERR_R(TPM2TSS_R_CANNOT_MAKE_KEY, Cannot create OpenSSL key object), ERR_R(TPM2TSS_R_SUBINIT_FAILED, Could not initialize submodule), ERR_R(TPM2TSS_R_FILE_WRITE, Could not create file for writing), ERR_R(TPM2TSS_R_DATA_CORRUPTED, Data is corrupted and could not be parsed), ERR_R(TPM2TSS_R_FILE_READ, Could not open file for reading), ERR_R(TPM2TSS_R_PADDING_UNKNOWN, Unknown padding scheme requested), ERR_R(TPM2TSS_R_PADDING_FAILED, Padding operation failed), ERR_R(TPM2TSS_R_UNKNOWN_TPM_ERROR, Unknown TPM error occurred. Please check tpm2tss logs), ERR_R(TPM2TSS_R_DIGEST_TOO_LARGE, The provided digest value is too large), ERR_R(TPM2TSS_R_GENERAL_FAILURE, Some unknown error occurred), ERR_R(TPM2TSS_R_UNKNOWN_CURVE, Unknown ECC curve), ERR_R(TPM2TSS_R_UI_ERROR, User interaction), ERR_R(TPM2TSS_R_UNKNOWN_CTRL, Unknown engine ctrl), ERR_R(TPM2TSS_R_DL_OPEN_FAILED, Failed to open TCTI library), ERR_R(TPM2TSS_R_DL_INVALID, The TCTI library is invalid), /* TPM/TSS Reasons that are useful to the user */ ERR_R(TPM2TSS_R_AUTH_FAILURE, Authorization failed), ERR_R(TPM2TSS_R_OWNER_AUTH_FAILED, Owner authorization failed), ERR_R(TPM2TSS_R_OLD_TSS, An old TSS (<2.2) was detected and a TPM session may have leaked), {0, NULL} }; #endif /* OPENSSL_NO_ERR */ static int TPM2TSS_lib_error_code = 0; static int TPM2TSS_error_init = 0; static ERR_STRING_DATA TPM2TSS_lib_name[] = { {0, TPM2TSS_LIB_NAME}, {0, NULL} }; /** Load TPM2TSS error string * * Load the errorstring from TPM2TSS_f and TPM2TSS_r into OpenSSL's error * handling stack. */ void ERR_load_TPM2TSS_strings(void) { if (TPM2TSS_lib_error_code == 0) TPM2TSS_lib_error_code = ERR_get_next_error_library(); if (!TPM2TSS_error_init) { TPM2TSS_error_init = 1; #ifndef OPENSSL_NO_ERR ERR_load_strings(TPM2TSS_lib_error_code, TPM2TSS_f); ERR_load_strings(TPM2TSS_lib_error_code, TPM2TSS_r); #endif /* OPENSSL_NO_ERR */ TPM2TSS_lib_name->error = ERR_PACK(TPM2TSS_lib_error_code, 0, 0); ERR_load_strings(0, TPM2TSS_lib_name); } } /** Unload TPM2TSS error string * * Unload the errorstring from TPM2TSS_f and TPM2TSS_r into OpenSSL's error * handling stack. */ void ERR_unload_TPM2TSS_strings(void) { if (TPM2TSS_error_init) { #ifndef OPENSSL_NO_ERR ERR_unload_strings(TPM2TSS_lib_error_code, TPM2TSS_f); ERR_unload_strings(TPM2TSS_lib_error_code, TPM2TSS_r); #endif /* OPENSSL_NO_ERR */ ERR_unload_strings(0, TPM2TSS_lib_name); TPM2TSS_error_init = 0; } } /** Add error to error stack * * Add the error to the error stack of OpenSSL. * This function is usually not called directly but using the macros ERR(f,r) * or ERRchktss(f, r, s) from source code. * @param function Identifier of the function invocing the error. * @param reason Identifier of the reason for the error. * @param file File from which the error originates. * @param line Line inside the file from which the error originates. */ void ERR_error(int function, int reason, const char *file, int line) { (void)(function); (void)(file); (void)(line); if (TPM2TSS_lib_error_code == 0) TPM2TSS_lib_error_code = ERR_get_next_error_library(); ERR_PUT_error(TPM2TSS_lib_error_code, function, reason, file, line); } /** Print a buffer to stderr * * A helper function to print data buffers to stderr. This function is usually * not called directly, but the macro DBGBUF() is used instead. * @param b The buffer * @param s The buffer's size */ void printbuf(const uint8_t *b, size_t s) { if (s > 1000) return; for (size_t i = 0; i < s; i++) fprintf(stderr, "%02x", b[i]); fprintf(stderr, "\n"); } 07070100000021000081A400000000000000000000000164643FF80000141F000000000000000000000000000000000000003D00000000tpm2-tss-engine-1684291576.28be674/src/tpm2-tss-engine-err.h/******************************************************************************* * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of tpm2-tss-engine nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #ifndef TPM2_TSS_ENGINE_ERR_H #define TPM2_TSS_ENGINE_ERR_H #include "config.h" #include <stdint.h> #ifndef NDEBUG #define DBG(...) fprintf(stderr, __VA_ARGS__) #define DBGBUF(...) printbuf(__VA_ARGS__) void printbuf(const uint8_t *b, size_t s); #else /* DEBUG */ #define DBG(...) #define DBGBUF(...) #endif /* DEBUG */ #define ERR(f,r) ERR_error(TPM2TSS_F_ ## f, r, __FILE__, __LINE__) /* This macro checks for common TPM error codes which are meaningful to the user */ #define ERRchktss(f, r, s) do { \ if (r) { \ switch(r) { \ case TSS2_ESYS_RC_MEMORY: \ ERR(f, ERR_R_MALLOC_FAILURE); \ break; \ case 0x000009a2: \ ERR(f, TPM2TSS_R_AUTH_FAILURE); \ break; \ default: \ ERR(f, TPM2TSS_R_UNKNOWN_TPM_ERROR); \ } \ s; \ } \ } while (0); void ERR_load_TPM2TSS_strings(void); void ERR_unload_TPM2TSS_strings(void); void ERR_error(int function, int reason, const char *file, int line); /* Function codes */ /* tpm2-tss-engine.c */ #define TPM2TSS_F_loadkey 100 #define TPM2TSS_F_init_engine 101 #define TPM2TSS_F_get_auth 102 #define TPM2TSS_F_engine_ctrl 103 /* tpm2-tss-engine-common.c */ #define TPM2TSS_F_tpm2tss_tpm2data_write 110 #define TPM2TSS_F_tpm2tss_tpm2data_read 111 #define TPM2TSS_F_tpm2tss_tpm2data_readtpm 112 #define TPM2TSS_F_init_tpm_parent 113 #define TPM2TSS_F_init_tpm_key 114 #define TPM2TSS_F_esys_ctx_init 115 #define TPM2TSS_F_esys_ctx_free 116 /* tpm2-tss-engine-ecc.c */ #define TPM2TSS_F_ecdsa_sign 120 #define TPM2TSS_F_populate_ecc 121 #define TPM2TSS_F_tpm2tss_ecc_genkey 122 #define TPM2TSS_F_tpm2tss_ecc_makekey 123 #define TPM2TSS_F_ecdh_compute_key 124 /* tpm2-tss-engine-digest-sign.c */ #define TPM2TSS_F_digest_init 150 #define TPM2TSS_F_digest_update 151 #define TPM2TSS_F_digest_finish 152 #define TPM2TSS_F_digest_sign_init 153 #define TPM2TSS_F_digest_sign_copy 154 /* tpm2-tss-engine-rand.c */ #define TPM2TSS_F_rand_bytes 130 #define TPM2TSS_F_rand_seed 131 /* tpm2-tss-engine-rsa.c */ #define TPM2TSS_F_rsa_priv_enc 140 #define TPM2TSS_F_rsa_priv_dec 141 #define TPM2TSS_F_tpm2tss_rsa_genkey 142 #define TPM2TSS_F_populate_rsa 143 #define TPM2TSS_F_rsa_signctx 144 /* Reason codes */ #define TPM2TSS_R_TPM2DATA_READ_FAILED 100 #define TPM2TSS_R_UNKNOWN_ALG 101 #define TPM2TSS_R_CANNOT_MAKE_KEY 102 #define TPM2TSS_R_SUBINIT_FAILED 103 #define TPM2TSS_R_FILE_WRITE 104 #define TPM2TSS_R_DATA_CORRUPTED 105 #define TPM2TSS_R_FILE_READ 106 #define TPM2TSS_R_PADDING_UNKNOWN 107 #define TPM2TSS_R_PADDING_FAILED 108 #define TPM2TSS_R_UNKNOWN_TPM_ERROR 109 #define TPM2TSS_R_DIGEST_TOO_LARGE 110 #define TPM2TSS_R_GENERAL_FAILURE 111 #define TPM2TSS_R_UNKNOWN_CURVE 112 #define TPM2TSS_R_UI_ERROR 113 #define TPM2TSS_R_UNKNOWN_CTRL 114 #define TPM2TSS_R_DL_OPEN_FAILED 115 #define TPM2TSS_R_DL_INVALID 116 /* TPM/TSS Reasons that are useful to the user */ #define TPM2TSS_R_AUTH_FAILURE 150 #define TPM2TSS_R_OWNER_AUTH_FAILED 151 #define TPM2TSS_R_OLD_TSS 152 #endif /* TPM2_TSS_ENGINE_ERR_H */ 07070100000022000081A400000000000000000000000164643FF8000011BD000000000000000000000000000000000000003E00000000tpm2-tss-engine-1684291576.28be674/src/tpm2-tss-engine-rand.c/******************************************************************************* * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of tpm2-tss-engine nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #include <string.h> #include <openssl/engine.h> #include <openssl/rand.h> #include <tss2/tss2_mu.h> #include <tss2/tss2_esys.h> #include "tpm2-tss-engine.h" #include "tpm2-tss-engine-common.h" /** rand seed * @retval 1 on success * @retval 0 on failure */ static int rand_seed(const void *seed, int seed_len) { ESYS_CONTEXT *esys_ctx = NULL; TSS2_RC r; r = esys_ctx_init(&esys_ctx); ERRchktss(rand_seed, r, goto end); TPM2B_SENSITIVE_DATA stir; size_t offset = 0; char *cur_data = (char*)seed; static const size_t tpm_random_stir_max_size = 128; while(offset < (size_t)seed_len) { size_t left = seed_len - offset; size_t chunk = left > tpm_random_stir_max_size ? tpm_random_stir_max_size : left; stir.size = chunk; memcpy(stir.buffer, cur_data + offset, chunk); r = Esys_StirRandom( esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &stir); ERRchktss(rand_seed, r, goto end); offset += chunk; } end: if(esys_ctx) esys_ctx_free(&esys_ctx); return (r == TSS2_RC_SUCCESS)? 1 : 0; } /** Genereate random values * * Use the TPM to generate a number of random values. * @param buf The buffer to write the random values to * @param num The amound of random bytes to generate * @retval 1 on success * @retval 0 on failure */ static int rand_bytes(unsigned char *buf, int num) { ESYS_CONTEXT *esys_ctx = NULL; TSS2_RC r; r = esys_ctx_init(&esys_ctx); ERRchktss(rand_bytes, r, goto end); TPM2B_DIGEST *b; while (num > 0) { r = Esys_GetRandom(esys_ctx, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, num, &b); ERRchktss(rand_bytes, r, goto end); memcpy(buf, &b->buffer, b->size); num -= b->size; buf += b->size; Esys_Free(b); } esys_ctx_free(&esys_ctx); end: return (r == TSS2_RC_SUCCESS); } /** Return the entropy status of the prng * * Since we provide real (TPM-based) randomness even for the pseudorand * function, our status is allways good. * @retval 1 allways good status */ static int rand_status() { return 1; } static RAND_METHOD rand_methods = { rand_seed, rand_bytes, NULL, /* cleanup() */ NULL, /* add() */ rand_bytes, /* pseudorand() */ rand_status /* status() */ }; /** Initialize the tpm2tss engine's rand submodule * * Initialize the tpm2tss engine's submodule by setting function pointer. * @param e The engine context. * @retval 1 on success * @retval 0 on failure */ int init_rand(ENGINE *e) { return ENGINE_set_RAND(e, &rand_methods); } 07070100000023000081A400000000000000000000000164643FF80000600D000000000000000000000000000000000000003D00000000tpm2-tss-engine-1684291576.28be674/src/tpm2-tss-engine-rsa.c/******************************************************************************* * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of tpm2-tss-engine nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #include <string.h> #include <openssl/engine.h> #include <tss2/tss2_esys.h> #include "tpm2-tss-engine.h" #include "tpm2-tss-engine-common.h" #define chkerr_goto(x) if (x) { DBG("%s:%i:%s: Error 0x%04x\n", __FILE__, \ __LINE__, __func__, x); goto error; } const RSA_METHOD *default_rsa = NULL; #if OPENSSL_VERSION_NUMBER < 0x10100000 RSA_METHOD rsa_methods; #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ RSA_METHOD *rsa_methods = NULL; #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ #ifdef HAVE_OPENSSL_DIGEST_SIGN static int (*rsa_pkey_orig_copy)(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src); static void (*rsa_pkey_orig_cleanup)(EVP_PKEY_CTX *ctx); #endif /* HAVE_OPENSSL_DIGEST_SIGN */ static int (*rsa_orig_finish)(RSA *rsa); static TPM2B_DATA allOutsideInfo = { .size = 0, }; static TPML_PCR_SELECTION allCreationPCR = { .count = 0, }; static TPM2B_PUBLIC keyTemplate = { .publicArea = { .type = TPM2_ALG_RSA, .nameAlg = ENGINE_HASH_ALG, .objectAttributes = (TPMA_OBJECT_USERWITHAUTH | TPMA_OBJECT_SIGN_ENCRYPT | TPMA_OBJECT_DECRYPT | TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT | TPMA_OBJECT_SENSITIVEDATAORIGIN | TPMA_OBJECT_NODA), .authPolicy.size = 0, .parameters.rsaDetail = { .symmetric = { .algorithm = TPM2_ALG_NULL, .keyBits.aes = 0, .mode.aes = 0, }, .scheme = { .scheme = TPM2_ALG_NULL, .details = {} }, .keyBits = 0, /* to be set by the genkey function */ .exponent = 0, /* to be set by the genkey function */ }, .unique.rsa.size = 0 } }; /** Sign data using a TPM key * * This function performs the encrypt function using the private key in RSA. * This operation is usually used to perform signature and authentication * operations. * @param flen Length of the from buffer. * @param from The data to be signed. * @param to The buffer to write the signature to. * @param rsa The rsa key object. * @param padding The padding scheme to be used. * @retval 0 on failure * @retval size Size of the returned signature */ static int rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { TPM2_DATA *tpm2Data = RSA_get_app_data(rsa); /* If this is not a TPM2 key, fall through to software functions */ if (tpm2Data == NULL) { DBG("Non-TPM key passed. Calling standard function.\n"); #if OPENSSL_VERSION_NUMBER < 0x10100000 return default_rsa->rsa_priv_enc(flen, from, to, rsa, padding); #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ return RSA_meth_get_priv_enc(default_rsa)(flen, from, to, rsa, padding); #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ } DBG("rsa_priv_enc called for scheme %i and input data(size=%i):\n", padding, flen); DBGBUF(from, flen); int ret = 0; TSS2_RC r = TSS2_RC_SUCCESS; ESYS_CONTEXT *esys_ctx = NULL; ESYS_TR keyHandle = ESYS_TR_NONE; TPM2B_DATA label = { .size = 0 }; TPM2B_PUBLIC_KEY_RSA *sig = NULL; TPMT_RSA_DECRYPT inScheme = { .scheme = TPM2_ALG_NULL }; TPM2B_PUBLIC_KEY_RSA digest; digest.size = RSA_size(rsa); if (digest.size > sizeof(digest.buffer)) { ERR(rsa_priv_enc, TPM2TSS_R_DIGEST_TOO_LARGE); goto error; } switch (padding) { case RSA_PKCS1_PADDING: ret = RSA_padding_add_PKCS1_type_1(&digest.buffer[0], digest.size, from, flen); break; case RSA_X931_PADDING: ret = RSA_padding_add_X931(&digest.buffer[0], digest.size, from, flen); break; case RSA_NO_PADDING: ret = RSA_padding_add_none(&digest.buffer[0], digest.size, from, flen); break; default: ERR(rsa_priv_enc, TPM2TSS_R_PADDING_UNKNOWN); goto error; } if (ret <= 0) { ERR(rsa_priv_enc, TPM2TSS_R_PADDING_FAILED); goto error; } DBG("Padded digest data (size=%i):\n", digest.size); DBGBUF(&digest.buffer[0], digest.size); r = init_tpm_key(&esys_ctx, &keyHandle, tpm2Data); ERRchktss(rsa_priv_enc, r, goto error); DBG("Signing (via decrypt operation).\n"); r = Esys_RSA_Decrypt(esys_ctx, keyHandle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &digest, &inScheme, &label, &sig); ERRchktss(rsa_priv_enc, r, goto error); DBG("Signature done (size=%i):\n", sig->size); DBGBUF(&sig->buffer[0], sig->size); ret = sig->size; if (ret > RSA_size(rsa) || ret <= 0) { ERR(rsa_priv_enc, TPM2TSS_R_DIGEST_TOO_LARGE); goto error; } memcpy(to, &sig->buffer[0], ret); goto out; error: r = -1; out: Esys_Free(sig); if (keyHandle != ESYS_TR_NONE) { if (tpm2Data->privatetype == KEY_TYPE_HANDLE) { Esys_TR_Close(esys_ctx, &keyHandle); } else { Esys_FlushContext(esys_ctx, keyHandle); } } esys_ctx_free(&esys_ctx); return (r == TSS2_RC_SUCCESS) ? ret : 0; } /** Decrypt data using a TPM key * * This function performs the decrypt function using the private key in RSA. * @param flen Length of the from buffer. * @param from The data to be decrypted. * @param to The buffer to write the plaintext to. * @param rsa The rsa key object. * @param padding The padding scheme to be used. * @retval 0 on failure * @retval size Size of the returned plaintext */ static int rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA * rsa, int padding) { TPM2_DATA *tpm2Data = RSA_get_app_data(rsa); /* If this is not a TPM2 key, fall through to software functions */ if (tpm2Data == NULL) #if OPENSSL_VERSION_NUMBER < 0x10100000 return default_rsa->rsa_priv_dec(flen, from, to, rsa, padding); #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ return RSA_meth_get_priv_dec(default_rsa)(flen, from, to, rsa, padding); #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ DBG("rsa_priv_dec called for scheme %i and input data(size=%i):\n", padding, flen); DBGBUF(from, flen); TSS2_RC r; ESYS_CONTEXT *esys_ctx = NULL; ESYS_TR keyHandle = ESYS_TR_NONE; TPM2B_DATA label = { .size = 0 }; TPM2B_PUBLIC_KEY_RSA *message = NULL; TPMT_RSA_DECRYPT inScheme; TPM2B_PUBLIC_KEY_RSA cipher = { .size = flen }; if (flen > (int)sizeof(cipher.buffer) || flen < 0) { ERR(rsa_priv_dec, TPM2TSS_R_DIGEST_TOO_LARGE); goto error; } memcpy(&cipher.buffer[0], from, flen); switch (padding) { case RSA_PKCS1_PADDING: inScheme.scheme = TPM2_ALG_RSAES; break; case RSA_PKCS1_OAEP_PADDING: inScheme.scheme = TPM2_ALG_OAEP; inScheme.details.oaep.hashAlg = TPM2_ALG_SHA1; break; case RSA_NO_PADDING: inScheme.scheme = TPM2_ALG_NULL; break; default: ERR(rsa_priv_dec, TPM2TSS_R_PADDING_UNKNOWN); goto error; } r = init_tpm_key(&esys_ctx, &keyHandle, tpm2Data); ERRchktss(rsa_priv_dec, r, goto out); r = Esys_RSA_Decrypt(esys_ctx, keyHandle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &cipher, &inScheme, &label, &message); ERRchktss(rsa_priv_dec, r, goto out); DBG("Decrypted message (size=%i):\n", message->size); DBGBUF(&message->buffer[0], message->size); flen = message->size; if (flen > RSA_size(rsa) || flen <= 0) { ERR(rsa_priv_dec, TPM2TSS_R_DIGEST_TOO_LARGE); goto error; } memcpy(to, &message->buffer[0], flen); goto out; error: r = -1; out: Esys_Free(message); if (keyHandle != ESYS_TR_NONE) { if (tpm2Data->privatetype == KEY_TYPE_HANDLE) { Esys_TR_Close(esys_ctx, &keyHandle); } else { Esys_FlushContext(esys_ctx, keyHandle); } } esys_ctx_free(&esys_ctx); return (r == TSS2_RC_SUCCESS) ? flen : 0; } /** Clean up the RSA key * * @param rsa The rsa key object. * @retval 1 on success, or 0 on failure */ static int rsa_finish(RSA *rsa) { TPM2_DATA *tpm2Data = RSA_get_app_data(rsa); if (tpm2Data != NULL) { OPENSSL_free(tpm2Data); RSA_set_app_data(rsa, NULL); } if (rsa_orig_finish) { rsa_orig_finish(rsa); } return 1; } /** Helper to populate the RSA key object. * * In order to use an RSA key object in a typical manner, all fields of the * OpenSSL's corresponding object bust be filled. This function fills the public * values correctly and fill the private values with 0. * @param rsa The key object to fill. * @retval 0 on failure * @retval 1 on success */ static int populate_rsa(RSA *rsa) { TPM2_DATA *tpm2Data = RSA_get_app_data(rsa); UINT32 exponent; if (tpm2Data == NULL) goto error; exponent = tpm2Data->pub.publicArea.parameters.rsaDetail.exponent; if (!exponent) exponent = 0x10001; #if OPENSSL_VERSION_NUMBER < 0x10100000 /* Setting the public portion of the key */ rsa->n = BN_bin2bn(tpm2Data->pub.publicArea.unique.rsa.buffer, tpm2Data->pub.publicArea.unique.rsa.size, rsa->n); if (rsa->n == NULL) { ERR(populate_rsa, ERR_R_MALLOC_FAILURE); goto error; } if (rsa->e == NULL) rsa->e = BN_new(); if (rsa->e == NULL) { ERR(populate_rsa, ERR_R_MALLOC_FAILURE); goto error; } BN_set_word(rsa->e, exponent); /* Setting private portions to 0 values so the public key can be extracted from the keyfile if this is desired. */ if (rsa->d == NULL) rsa->d = BN_new(); if (rsa->d == NULL) { ERR(populate_rsa, ERR_R_MALLOC_FAILURE); goto error; } BN_set_word(rsa->d, 0); if (rsa->p == NULL) rsa->p = BN_new(); if (rsa->p == NULL) { ERR(populate_rsa, ERR_R_MALLOC_FAILURE); goto error; } BN_set_word(rsa->p, 0); if (rsa->q == NULL) rsa->q = BN_new(); if (rsa->q == NULL) { ERR(populate_rsa, ERR_R_MALLOC_FAILURE); goto error; } BN_set_word(rsa->q, 0); if (rsa->dmp1 == NULL) rsa->dmp1 = BN_new(); if (rsa->dmp1 == NULL) { ERR(populate_rsa, ERR_R_MALLOC_FAILURE); goto error; } BN_set_word(rsa->dmp1, 0); if (rsa->dmq1 == NULL) rsa->dmq1 = BN_new(); if (rsa->dmq1 == NULL) { ERR(populate_rsa, ERR_R_MALLOC_FAILURE); goto error; } BN_set_word(rsa->dmq1, 0); if (rsa->iqmp == NULL) rsa->iqmp = BN_new(); if (rsa->iqmp == NULL) { ERR(populate_rsa, ERR_R_MALLOC_FAILURE); goto error; } BN_set_word(rsa->iqmp, 0); #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ BIGNUM *n = BN_bin2bn(tpm2Data->pub.publicArea.unique.rsa.buffer, tpm2Data->pub.publicArea.unique.rsa.size, NULL); BIGNUM *e = BN_new(); BIGNUM *d = BN_new(); BIGNUM *p = BN_new(); BIGNUM *q = BN_new(); BIGNUM *dmp1 = BN_new(); BIGNUM *dmq1 = BN_new(); BIGNUM *iqmp = BN_new(); if (!n || !e || !d || !p || !q || !dmp1 || !dmq1 || !iqmp) { if (n) BN_free(n); if (e) BN_free(e); if (d) BN_free(d); if (p) BN_free(p); if (q) BN_free(q); if (dmp1) BN_free(dmp1); if (dmq1) BN_free(dmq1); if (iqmp) BN_free(iqmp); ERR(populate_rsa, ERR_R_MALLOC_FAILURE); goto error; } BN_set_word(e, exponent); BN_set_word(d, 0); BN_set_word(p, 0); BN_set_word(q, 0); BN_set_word(dmp1, 0); BN_set_word(dmq1, 0); BN_set_word(iqmp, 0); RSA_set0_key(rsa, n, e, d); RSA_set0_factors(rsa, p, q); RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp); #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ return 1; error: return 0; } /** Helper to load an RSA key from a tpm2Data * * This function creates a key object given a TPM2_DATA object. The resulting * key object can then be used for signing and decrypting with the tpm2tss * engine. Ownership of the TPM2_DATA object is taken on success. * @param tpm2Data The key data to use. Must have been allocated using * OPENSSL_malloc. * @retval key The key object * @retval NULL on failure. */ EVP_PKEY * tpm2tss_rsa_makekey(TPM2_DATA *tpm2Data) { EVP_PKEY *pkey; RSA *rsa; DBG("Creating RSA key object.\n"); /* create the new objects to return */ if ((pkey = EVP_PKEY_new()) == NULL) { ERR(populate_rsa, ERR_R_MALLOC_FAILURE); return NULL; } if ((rsa = RSA_new()) == NULL) { ERR(populate_rsa, ERR_R_MALLOC_FAILURE); EVP_PKEY_free(pkey); return NULL; } #if OPENSSL_VERSION_NUMBER < 0x10100000 rsa->meth = &rsa_methods; #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ RSA_set_method(rsa, rsa_methods); #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ if (!EVP_PKEY_assign_RSA(pkey, rsa)) { ERR(populate_rsa, TPM2TSS_R_GENERAL_FAILURE); RSA_free(rsa); goto error; } if (!RSA_set_app_data(rsa, tpm2Data)) { ERR(populate_rsa, TPM2TSS_R_GENERAL_FAILURE); goto error; } if (!populate_rsa(rsa)) { RSA_set_app_data(rsa, NULL); goto error; } DBG("Created RSA key object.\n"); return pkey; error: EVP_PKEY_free(pkey); return NULL; } /** Generate a tpm2tss rsa key object. * * This function creates a new TPM RSA key. The TPM data is stored inside the * object*s app data and can be retrieved using RSA_get_app_data(). * @param rsa The key object for the TPM RSA key to be created. * @param bits The key size * @param e The key's exponent * @param password The Password to be set for the new key * @retval 1 on success * @retval 0 on failure */ int tpm2tss_rsa_genkey(RSA *rsa, int bits, BIGNUM *e, char *password, TPM2_HANDLE parentHandle) { DBG("Generating RSA key for %i bits keysize.\n", bits); TSS2_RC r = TSS2_RC_SUCCESS; ESYS_CONTEXT *esys_ctx = NULL; ESYS_TR parent = ESYS_TR_NONE; TPM2B_PUBLIC *keyPublic = NULL; TPM2B_PRIVATE *keyPrivate = NULL; TPM2_DATA *tpm2Data = NULL; TPM2B_PUBLIC inPublic = keyTemplate; TPM2B_SENSITIVE_CREATE inSensitive = { .sensitive = { .userAuth = { .size = 0, }, .data = { .size = 0, } } }; tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data)); if (tpm2Data == NULL) { ERR(tpm2tss_rsa_genkey, TPM2TSS_R_GENERAL_FAILURE); goto error; } memset(tpm2Data, 0, sizeof(*tpm2Data)); inPublic.publicArea.parameters.rsaDetail.keyBits = bits; if (e) inPublic.publicArea.parameters.rsaDetail.exponent = BN_get_word(e); if (password) { DBG("Setting a password for the created key.\n"); if (strlen(password) > sizeof(tpm2Data->userauth.buffer) - 1) { goto error; } tpm2Data->userauth.size = strlen(password); memcpy(&tpm2Data->userauth.buffer[0], password, tpm2Data->userauth.size); inSensitive.sensitive.userAuth.size = strlen(password); memcpy(&inSensitive.sensitive.userAuth.buffer[0], password, strlen(password)); } else tpm2Data->emptyAuth = 1; r = init_tpm_parent(&esys_ctx, parentHandle, &parent); ERRchktss(tpm2tss_rsa_genkey, r, goto error); tpm2Data->parent = parentHandle; DBG("Generating the RSA key inside the TPM.\n"); r = Esys_Create(esys_ctx, parent, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &inSensitive, &inPublic, &allOutsideInfo, &allCreationPCR, &keyPrivate, &keyPublic, NULL, NULL, NULL); ERRchktss(tpm2tss_rsa_genkey, r, goto error); DBG("Generated the RSA key inside the TPM.\n"); tpm2Data->pub = *keyPublic; tpm2Data->priv = *keyPrivate; if (!RSA_set_app_data(rsa, tpm2Data)) { ERR(tpm2tss_rsa_genkey, TPM2TSS_R_GENERAL_FAILURE); goto error; } if (!populate_rsa(rsa)) { goto error; } goto end; error: r = -1; if (rsa) RSA_set_app_data(rsa, NULL); if (tpm2Data) OPENSSL_free(tpm2Data); end: Esys_Free(keyPrivate); Esys_Free(keyPublic); if (parent != ESYS_TR_NONE && !parentHandle) Esys_FlushContext(esys_ctx, parent); esys_ctx_free(&esys_ctx); return (r == TSS2_RC_SUCCESS); } #if OPENSSL_VERSION_NUMBER < 0x10100000 RSA_METHOD rsa_methods = { "TPM2TSS RSA methods", NULL, /* tpm_rsa_pub_enc */ NULL, /* tpm_rsa_pub_dec */ rsa_priv_enc, /* act sign */ rsa_priv_dec, /* act decrypt */ NULL, /* rsa_mod_exp */ NULL, /* bn_mod_exp */ NULL, /* init */ NULL, /* finish */ 0, NULL, /* app_data */ NULL, /* sign */ NULL, /* verify */ NULL /* genkey */ }; #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ #ifdef HAVE_OPENSSL_DIGEST_SIGN static int rsa_pkey_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { if (rsa_pkey_orig_copy && !rsa_pkey_orig_copy(dst, src)) return 0; return digest_sign_copy(dst, src); } static void rsa_pkey_cleanup(EVP_PKEY_CTX *ctx) { digest_sign_cleanup(ctx); if (rsa_pkey_orig_cleanup) rsa_pkey_orig_cleanup(ctx); } /* called for digest & sign init, after message digest algorithm set */ static int rsa_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) { EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx); RSA *rsa = EVP_PKEY_get0_RSA(pkey); TPM2_DATA *tpm2data = RSA_get_app_data(rsa); DBG("rsa_digest_custom %p %p\n", ctx, mctx); return digest_sign_init(ctx, mctx, tpm2data, RSA_size(rsa)); } static int rsa_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, EVP_MD_CTX *mctx) { TPM2_SIG_DATA *sig_data = EVP_PKEY_CTX_get_app_data(ctx); TSS2_RC r = TSS2_RC_SUCCESS; TPMT_TK_HASHCHECK *validation_ptr = NULL; TPM2B_DIGEST *digest_ptr = NULL; TPMT_SIGNATURE *tpm_sig = NULL; int pad_mode; DBG("rsa_signctx %p %p sig_data %p\n", ctx, mctx, sig_data); if (!sig) { /* caller just wants to know the size */ *siglen = sig_data->sig_size; return 1; } if (!sig_data) { /* handle non-TPM key */ unsigned char md[EVP_MAX_MD_SIZE]; unsigned int md_len = 0; if (!EVP_DigestFinal_ex(mctx, md, &md_len)) return 0; if (EVP_PKEY_sign(ctx, sig, siglen, md, md_len) <= 0) return 0; return 1; } if (EVP_PKEY_CTX_get_rsa_padding(ctx, &pad_mode) <= 0) return 0; TPMT_SIG_SCHEME in_scheme = { .scheme = TPM2_ALG_NULL, .details.rsassa.hashAlg = sig_data->hash_alg, }; switch (pad_mode) { case RSA_PKCS1_PADDING: in_scheme.scheme = TPM2_ALG_RSASSA; break; case RSA_PKCS1_PSS_PADDING: in_scheme.scheme = TPM2_ALG_RSAPSS; break; default: ERR(rsa_signctx, TPM2TSS_R_PADDING_UNKNOWN); return 0; } if (!digest_finish(sig_data, &digest_ptr, &validation_ptr)) return 0; r = Esys_Sign(sig_data->key->esys_ctx, sig_data->key->key_handle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, digest_ptr, &in_scheme, validation_ptr, &tpm_sig); ERRchktss(rsa_signctx, r, goto error); memcpy(sig, tpm_sig->signature.rsassa.sig.buffer, sig_data->sig_size); *siglen = sig_data->sig_size; r = 1; goto out; error: r = 0; out: Esys_Free(tpm_sig); Esys_Free(digest_ptr); Esys_Free(validation_ptr); return r; } #endif /* HAVE_OPENSSL_DIGEST_SIGN */ /** Initialize the tpm2tss engine's rsa submodule * * Initialize the tpm2tss engine's submodule by setting function pointer. * @param e The engine context. * @retval 1 on success * @retval 0 on failure */ int init_rsa(ENGINE *e) { #if OPENSSL_VERSION_NUMBER < 0x10100000 default_rsa = RSA_PKCS1_SSLeay(); if (default_rsa == NULL) return 0; rsa_methods.rsa_pub_enc = default_rsa->rsa_pub_enc; rsa_methods.rsa_pub_dec = default_rsa->rsa_pub_dec; rsa_methods.rsa_mod_exp = default_rsa->rsa_mod_exp; rsa_methods.bn_mod_exp = default_rsa->bn_mod_exp; if (!ENGINE_set_RSA(e, &rsa_methods)) return 0; #else /* OPENSSL_VERSION_NUMBER < 0x10100000 */ default_rsa = RSA_PKCS1_OpenSSL(); if (default_rsa == NULL) return 0; rsa_methods = RSA_meth_dup(default_rsa); RSA_meth_set1_name(rsa_methods, "TPM2TSS RSA methods"); RSA_meth_set_priv_enc(rsa_methods, rsa_priv_enc); RSA_meth_set_priv_dec(rsa_methods, rsa_priv_dec); rsa_orig_finish = RSA_meth_get_finish(rsa_methods); RSA_meth_set_finish(rsa_methods, rsa_finish); if (!ENGINE_set_RSA(e, rsa_methods)) return 0; #endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ #if HAVE_OPENSSL_DIGEST_SIGN /* digest and sign support */ EVP_PKEY_METHOD *pkey_rsa_methods; pkey_rsa_methods = EVP_PKEY_meth_new(EVP_PKEY_RSA, EVP_PKEY_FLAG_AUTOARGLEN); if (pkey_rsa_methods == NULL) return 0; const EVP_PKEY_METHOD *pkey_orig_rsa_methods = EVP_PKEY_meth_find(EVP_PKEY_RSA); if (pkey_orig_rsa_methods == NULL) return 0; EVP_PKEY_meth_copy(pkey_rsa_methods, pkey_orig_rsa_methods); /* * save originals since we only override some of the pkey * functionality, rather than reimplementing all of it */ EVP_PKEY_meth_get_copy(pkey_rsa_methods, &rsa_pkey_orig_copy); EVP_PKEY_meth_get_cleanup(pkey_rsa_methods, &rsa_pkey_orig_cleanup); EVP_PKEY_meth_set_copy(pkey_rsa_methods, rsa_pkey_copy); EVP_PKEY_meth_set_cleanup(pkey_rsa_methods, rsa_pkey_cleanup); EVP_PKEY_meth_set_signctx(pkey_rsa_methods, NULL, rsa_signctx); EVP_PKEY_meth_set_digest_custom(pkey_rsa_methods, rsa_digest_custom); EVP_PKEY_meth_add0(pkey_rsa_methods); #endif /* HAVE_OPENSSL_DIGEST_SIGN */ return 1; } 07070100000024000081A400000000000000000000000164643FF8000028A1000000000000000000000000000000000000003900000000tpm2-tss-engine-1684291576.28be674/src/tpm2-tss-engine.c/******************************************************************************* * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of tpm2-tss-engine nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #include "config.h" #include <stdlib.h> #include <string.h> #include <openssl/engine.h> #include <openssl/pem.h> #include <openssl/ec.h> #include <openssl/ecdsa.h> #include <tss2/tss2_mu.h> #include <tss2/tss2_esys.h> #include "tpm2-tss-engine.h" #include "tpm2-tss-engine-common.h" /** * The identifier of the engine */ static const char *engine_id = "tpm2tss"; /** * The full name of the engine */ static const char *engine_name = "TPM2-TSS engine for OpenSSL"; TPM2B_DIGEST ownerauth = { .size = 0 }; TPM2B_DIGEST parentauth = { .size = 0 }; char *tcti_nameconf = NULL; /** Retrieve password * * Helper function to retreive a password from the user. * @param prompt_info [in] The object name to ask the user for * @param ui_method [in] The ui method callbacks to be used * @param cb_data [in] The callback data for the ui * @param auth [out] The user provided password * @retval 1 on success * @retval 0 on failure */ static int get_auth(const char *prompt_info, UI_METHOD *ui_method, void *cb_data, TPM2B_AUTH *auth) { DBG("get_auth called for object %s with ui_method %p\n", prompt_info, ui_method); char *ui_prompt = NULL; UI *ui = NULL; if (!ui_method) { ERR(get_auth, TPM2TSS_R_UI_ERROR); goto error; } ui = UI_new_method(ui_method); if (!ui) { ERR(get_auth, TPM2TSS_R_UI_ERROR); goto error; } ui_prompt = UI_construct_prompt(ui, "password", prompt_info); if (!ui_prompt) { ERR(get_auth, TPM2TSS_R_UI_ERROR); goto error; } if (0 > UI_add_input_string(ui, ui_prompt, UI_INPUT_FLAG_DEFAULT_PWD, (char *)&auth->buffer[0], 0, sizeof(auth->buffer) - 1)) { ERR(get_auth, TPM2TSS_R_UI_ERROR); goto error; } UI_add_user_data(ui, cb_data); if (0 > UI_process(ui)) { ERR(get_auth, TPM2TSS_R_UI_ERROR); goto error; } auth->size = strlen((char *)&auth->buffer[0]); OPENSSL_free(ui_prompt); UI_free(ui); DBG("password is %s\n", (char *)&auth->buffer[0]); return 1; error: if (ui_prompt) OPENSSL_free(ui_prompt); if (ui) UI_free(ui); return 0; } static const ENGINE_CMD_DEFN cmd_defns[] = { { TPM2TSS_SET_OWNERAUTH, "SET_OWNERAUTH", "Set the password for the owner hierarchy (default none)", ENGINE_CMD_FLAG_STRING }, { TPM2TSS_SET_TCTI, "SET_TCTI", "Set the TCTI module and options (default none)", ENGINE_CMD_FLAG_STRING }, { TPM2TSS_SET_PARENTAUTH, "SET_PARENTAUTH", "Set the password for the parent key (default none)", ENGINE_CMD_FLAG_STRING }, {0, NULL, NULL, 0} }; static int engine_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) ()) { (void)(e); (void)(i); (void)(f); switch (cmd) { case TPM2TSS_SET_OWNERAUTH: if (!p) { DBG("Setting owner auth to empty auth.\n"); ownerauth.size = 0; return 1; } DBG("Setting owner auth to password.\n"); if (strlen((char *)p) > sizeof(ownerauth.buffer) - 1) { return 0; } ownerauth.size = strlen((char *)p); memcpy(&ownerauth.buffer[0], p, ownerauth.size); return 1; case TPM2TSS_SET_TCTI: OPENSSL_free(tcti_nameconf); if (!p) { DBG("Setting TCTI to the ESAPI default\n"); } else { tcti_nameconf = OPENSSL_strdup(p); DBG("Setting TCTI option to \"%s\"\n", tcti_nameconf); } return 1; case TPM2TSS_SET_PARENTAUTH: if (!p) { DBG("Setting parent auth to empty auth.\n"); parentauth.size = 0; return 1; } DBG("Setting parent auth to password.\n"); if (strlen((char *)p) > sizeof(parentauth.buffer) - 1) { return 0; } parentauth.size = strlen((char *)p); memcpy(&parentauth.buffer[0], p, parentauth.size); return 1; default: break; } ERR(engine_ctrl, TPM2TSS_R_UNKNOWN_CTRL); return 0; } /** Load a TPM2TSS key * * This function implements the prototype for loading a key from a file. * @param e The engine for this callback (unused). * @param key_id The name of the file with the TPM key data. * @param ui The ui functions for querying the user. * @param cb_data Callback data. */ static EVP_PKEY * loadkey(ENGINE *e, const char *key_id, UI_METHOD *ui, void *cb_data) { (void)(e); (void)(ui); (void)(cb_data); TPM2_DATA *tpm2Data = NULL; EVP_PKEY *pkey = NULL; DBG("Loading private key %s\n", key_id); if (strncmp(key_id, "0x81", 4) == 0) { uint32_t handle; sscanf(key_id, "0x%x", &handle); if (!tpm2tss_tpm2data_readtpm(handle, &tpm2Data)) { ERR(loadkey, TPM2TSS_R_TPM2DATA_READ_FAILED); goto error; } } else { if (!tpm2tss_tpm2data_read(key_id, &tpm2Data)) { ERR(loadkey, TPM2TSS_R_TPM2DATA_READ_FAILED); goto error; } } if (tpm2Data->emptyAuth) { tpm2Data->userauth.size = 0; } else { if (!get_auth("user key", ui, cb_data, &tpm2Data->userauth)) { goto error; } } DBG("Loaded key uses alg-id %x\n", tpm2Data->pub.publicArea.type); switch (tpm2Data->pub.publicArea.type) { case TPM2_ALG_RSA: pkey = tpm2tss_rsa_makekey(tpm2Data); break; case TPM2_ALG_ECC: pkey = tpm2tss_ecc_makekey(tpm2Data); break; default: ERR(loadkey, TPM2TSS_R_UNKNOWN_ALG); goto error; } if (!pkey) { ERR(loadkey, TPM2TSS_R_CANNOT_MAKE_KEY); goto error; } DBG("TPM2 Key loaded\n"); return pkey; error: if (tpm2Data) OPENSSL_free(tpm2Data); return NULL; } /** Initialize the tpm2tss engine * * Initialize the tpm2tss engine by calling each of the submodules' init * functions for setting function pointer. * @param e The engine context. * @retval 1 on success * @retval 0 on failure */ static int init_engine(ENGINE *e) { static int initialized = 0; DBG("Initializing\n"); if (initialized) { DBG("Already initialized\n"); return 1; } int rc; #ifdef ENABLE_TCTIENVVAR /* Set the default TCTI option from the environment */ OPENSSL_free(tcti_nameconf); if (getenv("TPM2TSSENGINE_TCTI")) { tcti_nameconf = OPENSSL_strdup(getenv("TPM2TSSENGINE_TCTI")); } #endif rc = init_rand(e); if (rc != 1) { ERR(init_engine, TPM2TSS_R_SUBINIT_FAILED); return rc; } rc = init_rsa(e); if (rc != 1) { ERR(init_engine, TPM2TSS_R_SUBINIT_FAILED); return rc; } rc = init_ecc(e); if (rc != 1) { ERR(init_engine, TPM2TSS_R_SUBINIT_FAILED); return rc; } initialized = 1; return 1; } /** Destroys the engine context * * Unloads the strings of the tpm2tss engine. * @param e The engine context (unused). * @retval 1 for success */ static int destroy_engine(ENGINE *e) { (void)(e); OPENSSL_free(tcti_nameconf); ERR_unload_TPM2TSS_strings(); return 1; } /** OpenSSL's method to bind an engine. * * This initializes the name, id and function pointers of the engine. * @param e The TPM engine to initialize * @param id The identifier of the engine * @retval 0 if binding failed * @retval 1 on success */ static int bind(ENGINE *e, const char *id) { (void)(id); if (!ENGINE_set_id(e, engine_id)) { DBG("ENGINE_set_id failed\n"); goto end; } if (!ENGINE_set_name(e, engine_name)) { DBG("ENGINE_set_name failed\n"); goto end; } /* The init function is not allways called so we initialize crypto methods directly from bind. */ if (!init_engine(e)) { DBG("tpm2tss enigne initialization failed\n"); goto end; } if (!ENGINE_set_load_privkey_function(e, loadkey)) { DBG("ENGINE_set_load_privkey_function failed\n"); goto end; } if (!ENGINE_set_destroy_function(e, destroy_engine)) { DBG("ENGINE_set_destroy_function failed\n"); goto end; } if (!ENGINE_set_ctrl_function(e, engine_ctrl)) { DBG("ENGINE_set_ctrl_function failed\n"); goto end; } if (!ENGINE_set_cmd_defns(e, cmd_defns)) { DBG("ENGINE_set_cmd_defns failed\n"); goto end; } ERR_load_TPM2TSS_strings(); return 1; end: return 0; } IMPLEMENT_DYNAMIC_BIND_FN(bind) IMPLEMENT_DYNAMIC_CHECK_FN() 07070100000025000081A400000000000000000000000164643FF800002F93000000000000000000000000000000000000003800000000tpm2-tss-engine-1684291576.28be674/src/tpm2tss-genkey.c/******************************************************************************* * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of tpm2-tss-engine nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ #include <string.h> #include <strings.h> #include <inttypes.h> #include <unistd.h> #include <getopt.h> #include <openssl/conf.h> #include <openssl/engine.h> #include <openssl/pem.h> #include "tpm2-tss-engine.h" #include "tpm2-tss-engine-common.h" /* This tool uses a different error reporting scheme than the lib. */ #undef ERR #define VERB(...) if (opt.verbose) fprintf(stderr, __VA_ARGS__) #define ERR(...) fprintf(stderr, __VA_ARGS__) char *help = "Usage: [options] <filename>\n" "Arguments:\n" " <filename> storage for the encrypted private key\n" "Options:\n" " -a, --alg public key algorithm (rsa, ecdsa) (default: rsa)\n" " -c, --curve curve for ecc (default: nist_p256)\n" " -e, --exponent exponent for rsa (default: 65537)\n" " -h, --help print help\n" " -u, --public import a key and read its public portion from this file\n" " -r, --private import the sensitive key portion from this file\n" " -o, --ownerpw password for the owner hierarchy (default: none)\n" " -p, --password password for the created key (default: none)\n" " -P, --parent specific handle for the parent key (default: none)\n" " -s, --keysize key size in bits for rsa (default: 2048)\n" " -v, --verbose print verbose messages\n" " -W, --parentpw password for the parent key (default: none)\n" " -t, --tcti tcti configuration string (default: none)\n" "\n"; static const char *optstr = "a:c:e:hu:r:o:p:P:s:vW:t:"; static const struct option long_options[] = { {"alg", required_argument, 0, 'a'}, {"curve", required_argument, 0, 'c'}, {"exponent", required_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"public", required_argument, 0, 'u'}, {"private", required_argument, 0, 'r'}, {"ownerpw", required_argument, 0, 'o'}, {"password", required_argument, 0, 'p'}, {"parent", required_argument, 0, 'P'}, {"keysize", required_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"parentpw", required_argument, 0, 'W'}, {"tcti", required_argument, 0, 't'}, {0, 0, 0, 0 } }; static struct opt { char *filename; TPMI_ALG_PUBLIC alg; TPMI_ECC_CURVE curve; int exponent; char *importpub; char *importtpm; char *ownerpw; char *password; TPM2_HANDLE parent; char *parentpw; int keysize; int verbose; char *tcti_conf; } opt; /** Parse and set command line options. * * This function parses the command line options and sets the appropriate values * in the opt struct. * @param argc The argument count. * @param argv The arguments. * @retval 0 on success * @retval 1 on failure */ int parse_opts(int argc, char **argv) { /* set the default values */ opt.filename = NULL; opt.alg = TPM2_ALG_RSA; opt.curve = TPM2_ECC_NIST_P256; opt.exponent = 65537; opt.importpub = NULL; opt.importtpm = NULL; opt.ownerpw = NULL; opt.password = NULL; opt.parent = 0; opt.parentpw = NULL; opt.keysize = 2048; opt.verbose = 0; opt.tcti_conf = NULL; /* parse the options */ int c; int opt_idx = 0; while (-1 != (c = getopt_long(argc, argv, optstr, long_options, &opt_idx))) { switch(c) { case 'h': printf("%s", help); exit(0); case 'v': opt.verbose = 1; break; case 'a': if (strcasecmp(optarg, "rsa") == 0) { opt.alg = TPM2_ALG_RSA; break; } else if (strcasecmp(optarg, "ecdsa") == 0) { opt.alg = TPM2_ALG_ECDSA; break; } else { ERR("Unknown algorithm.\n"); exit(1); } case 'c': if (strcasecmp(optarg, "nist_p256") == 0) { opt.curve = TPM2_ECC_NIST_P256; break; } else if (strcasecmp(optarg, "nist_p384") == 0) { opt.curve = TPM2_ECC_NIST_P384; break; } else { ERR("Unknown curve.\n"); exit(1); } case 'e': if (sscanf(optarg, "%i", &opt.exponent) != 1) { ERR("Error parsing keysize.\n"); exit(1); } break; case 'u': opt.importpub = optarg; break; case 'r': opt.importtpm = optarg; break; case 'o': opt.ownerpw = optarg; break; case 'p': opt.password = optarg; break; case 'P': if (sscanf(optarg, "%x", &opt.parent) != 1 && sscanf(optarg, "0x%x", &opt.parent) != 1 && sscanf(optarg, "%i", &opt.parent) != 1) { ERR("Error parsing parent handle"); exit(1); } break; case 'W': opt.parentpw = optarg; break; case 's': if (sscanf(optarg, "%i", &opt.keysize) != 1) { ERR("Error parsing keysize.\n"); exit(1); } break; case 't': opt.tcti_conf = optarg; break; default: ERR("Unknown option at index %i.\n\n", opt_idx); ERR("%s", help); exit(1); } } /* parse the non-option arguments */ if (optind >= argc) { ERR("Missing argument <filename>.\n\n"); ERR("%s", help); exit(1); } opt.filename = argv[optind]; optind++; if (optind < argc) { ERR("Unknown argument provided.\n\n"); ERR("%s", help); exit(1); } if (!!opt.importpub != !!opt.importtpm) { ERR("Import requires both --public and --private\n"); return 1; } return 0; } /** Generate an RSA key * * This function calls out to generate an RSA key using the TPM. * @retval TPM2_DATA data to be written to disk * @retval NULL on failure */ static TPM2_DATA * genkey_rsa() { VERB("Generating RSA key using TPM\n"); RSA *rsa = NULL; BIGNUM *e = BN_new(); if (!e) { ERR("out of memory\n"); return NULL; } BN_set_word(e, opt.exponent); rsa = RSA_new(); if (!rsa) { ERR("out of memory\n"); BN_free(e); return NULL; } if (!tpm2tss_rsa_genkey(rsa, opt.keysize, e, opt.password, opt.parent)) { BN_free(e); RSA_free(rsa); ERR("Error: Generating key failed\n"); return NULL; } VERB("Key generated\n"); TPM2_DATA *tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data)); if (tpm2Data == NULL) { ERR("out of memory\n"); BN_free(e); RSA_free(rsa); return NULL; } memcpy(tpm2Data, RSA_get_app_data(rsa), sizeof(*tpm2Data)); BN_free(e); RSA_free(rsa); return tpm2Data; } /** Generate an ECDSA key * * This function calls out to generate an ECDSA key using the TPM. * @retval TPM2_DATA data to be written to disk * @retval NULL on failure */ static TPM2_DATA * genkey_ecdsa() { EC_KEY *eckey = NULL; eckey = EC_KEY_new(); if (!eckey) { ERR("out of memory\n"); return NULL; } if (!tpm2tss_ecc_genkey(eckey, opt.curve, opt.password, opt.parent)) { EC_KEY_free(eckey); ERR("Error: Generating key failed\n"); return NULL; } TPM2_DATA *tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data)); if (tpm2Data == NULL) { ERR("out of memory\n"); EC_KEY_free(eckey); return NULL; } memcpy(tpm2Data, tpm2tss_ecc_getappdata(eckey), sizeof(*tpm2Data)); EC_KEY_free(eckey); return tpm2Data; } /** Main function * * This function initializes OpenSSL and then calls the key generation * functions. * @param argc The argument count. * @param argv The arguments. * @retval 0 on success * @retval 1 on failure */ int main(int argc, char **argv) { if (parse_opts(argc, argv) != 0) exit(1); int r; TPM2_DATA *tpm2Data = NULL; #if OPENSSL_VERSION_NUMBER < 0x1010000fL OPENSSL_config(NULL); #else OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); #endif /* Initialize the tpm2-tss engine */ ENGINE_load_dynamic(); /* Openssl 1.1.0 requires the lib-prefix for the engine_id */ ENGINE *tpm_engine = ENGINE_by_id("tpm2tss"); if (!tpm_engine) tpm_engine = ENGINE_by_id("libtpm2tss"); if (tpm_engine == NULL) { ERR("Could not load tpm2tss engine\n"); return 1; } int init_res = ENGINE_init(tpm_engine); VERB("Engine name: %s\nInit result: %d \n", ENGINE_get_name(tpm_engine), init_res); if (!init_res) return 1; if (opt.ownerpw && !ENGINE_ctrl(tpm_engine, TPM2TSS_SET_OWNERAUTH, 0, opt.ownerpw, NULL)) { ERR("Could not set ownerauth\n"); return 1; } if (opt.parentpw && !ENGINE_ctrl(tpm_engine, TPM2TSS_SET_PARENTAUTH, 0, opt.parentpw, NULL)) { ERR("Could not set parentauth\n"); return 1; } if (opt.tcti_conf && !ENGINE_ctrl(tpm_engine, TPM2TSS_SET_TCTI, 0, opt.tcti_conf, NULL)) { ERR("Could not set parentauth\n"); return 1; } if (opt.importpub && opt.importtpm) { VERB("Importing the TPM key\n"); r = tpm2tss_tpm2data_importtpm(opt.importpub, opt.importtpm, opt.parent, opt.password == NULL, &tpm2Data); if (r != 1) return 1; } else switch (opt.alg) { case TPM2_ALG_RSA: VERB("Generating the rsa key\n"); tpm2Data = genkey_rsa(); break; case TPM2_ALG_ECDSA: VERB("Generating the ecdsa key\n"); tpm2Data = genkey_ecdsa(); break; default: break; } if (tpm2Data == NULL) { ERR("Key could not be generated.\n"); return 1; } /* Write the key to disk */ VERB("Writing key to disk\n"); if (!tpm2tss_tpm2data_write(tpm2Data, opt.filename)) { ERR("Error writing file\n"); OPENSSL_free(tpm2Data); return 1; } OPENSSL_free(tpm2Data); VERB("*** SUCCESS ***\n"); return 0; } 07070100000026000041ED00000000000000000000000264643FF800000000000000000000000000000000000000000000002800000000tpm2-tss-engine-1684291576.28be674/test07070100000027000081ED00000000000000000000000164643FF80000094E000000000000000000000000000000000000003000000000tpm2-tss-engine-1684291576.28be674/test/ecdh.sh#!/bin/bash set -euf # Create a primary key pair echo "Generating primary key" PARENT_CTX=primary_owner_key.ctx tpm2_createprimary --hierarchy=o \ --key-algorithm=ecc \ --hash-algorithm=sha256 \ --key-context=${PARENT_CTX} # Create an ECDH key pair echo "Generating ECDH key pair" ECDH_TPM_PUBKEY=ecdhtpm.pub ECDH_TPM_KEY=ecdhtpm tpm2_create --key-auth=abc \ --parent-context=${PARENT_CTX} \ --key-algorithm=ecc256:ecdh-sha256 \ --public=${ECDH_TPM_PUBKEY} \ --private=${ECDH_TPM_KEY} \ --attributes fixedparent\|fixedtpm\|decrypt\|sensitivedataorigin\|userwithauth\|noda tpm2_flushcontext --transient-object # Load key to persistent handle ECDH_CTX=ecdhkey.ctx tpm2_load --parent-context=${PARENT_CTX} \ --public=${ECDH_TPM_PUBKEY} \ --private=${ECDH_TPM_KEY} \ --key-context=${ECDH_CTX} tpm2_flushcontext --transient-object HANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${ECDH_CTX} | cut -d ' ' -f 2 | head -n 1) tpm2_flushcontext --transient-object # Get public key of handle ECDH_TPM_PUBKEY_PEM=ecdhtpm.pem tpm2_readpublic --object-context=${HANDLE} --output=${ECDH_TPM_PUBKEY_PEM} --format=pem # Generate peer key pair ECDH_PEER_PUBKEY=echdpeer.pub ECDH_PEER_KEY=ecdhpeer openssl ecparam -name prime256v1 -genkey -noout -out ${ECDH_PEER_KEY} openssl ec -in ${ECDH_PEER_KEY} -pubout -out ${ECDH_PEER_PUBKEY} # Perform ECDH using the TPM key pair as the private key and the peer key pair as the public key SECRET0=$(echo "abc" | openssl pkeyutl -derive -engine tpm2tss -keyform engine -inkey ${HANDLE} -peerkey ${ECDH_PEER_PUBKEY} -peerform pem -passin stdin | base64) echo -e "TPM(prv) <-> PEER(pub): ${SECRET0}" # Perform ECDH with the peer key pair as the private key and the TPM key pair as the public key SECRET1=$(openssl pkeyutl -derive -inkey ${ECDH_PEER_KEY} -peerkey ${ECDH_TPM_PUBKEY_PEM} -peerform pem | base64) echo -e "TPM(pub) <-> PEER(prv): ${SECRET1}" # Release persistent HANDLE and remove files tpm2_evictcontrol --object-context=${HANDLE} rm ${ECDH_PEER_KEY} ${ECDH_PEER_PUBKEY} ${ECDH_TPM_PUBKEY} ${ECDH_TPM_KEY} ${ECDH_TPM_PUBKEY_PEM} ${ECDH_CTX} # Ensure tpm and peer generated secrets are the same if [ "${SECRET0}" != "${SECRET1}" ]; then echo "secrets don't match" exit 1 fi 07070100000028000081ED00000000000000000000000164643FF800000194000000000000000000000000000000000000003B00000000tpm2-tss-engine-1684291576.28be674/test/ecdsa-emptyauth.sh#!/bin/bash set -eufx echo -n "abcde12345abcde12345">mydata tpm2tss-genkey -a ecdsa -c nist_p256 mykey openssl pkeyutl -keyform engine -engine tpm2tss -inkey mykey -sign -in mydata -out mysig R="$(openssl pkeyutl -keyform engine -engine tpm2tss -inkey mykey -verify -in mydata -sigfile mysig || true)" if ! echo $R | grep "Signature Verified Successfully" >/dev/null; then echo $R exit 1 fi 07070100000029000081ED00000000000000000000000164643FF8000006FB000000000000000000000000000000000000003E00000000tpm2-tss-engine-1684291576.28be674/test/ecdsa-handle-flush.sh#!/bin/bash set -eufx echo -n "abcde12345abcde12345">mydata.txt # Create a Primary key pair echo "Generating primary key" PARENT_CTX=primary_owner_key.ctx tpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=ecc \ --key-context=${PARENT_CTX} tpm2_flushcontext --transient-object # Create an ECDSA key pair echo "Generating ECDSA key pair" TPM_ECDSA_PUBKEY=ecdsakey.pub TPM_ECDSA_KEY=ecdsakey tpm2_create --key-auth=abc \ --parent-context=${PARENT_CTX} \ --hash-algorithm=sha256 --key-algorithm=ecc \ --public=${TPM_ECDSA_PUBKEY} --private=${TPM_ECDSA_KEY} \ --attributes=sign\|decrypt\|fixedtpm\|fixedparent\|sensitivedataorigin\|userwithauth\|noda tpm2_flushcontext --transient-object # Load Key to persistent handle ECDSA_CTX=ecdsakey.ctx tpm2_load --parent-context=${PARENT_CTX} \ --public=${TPM_ECDSA_PUBKEY} --private=${TPM_ECDSA_KEY} \ --key-context=${ECDSA_CTX} tpm2_flushcontext --transient-object HANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${ECDSA_CTX} | cut -d ' ' -f 2 | head -n 1) tpm2_flushcontext --transient-object # Signing Data R="$(echo "abc" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey ${HANDLE} -sign -in mydata.txt -out mysig -passin stdin 2>&1 || true)" if echo $R | grep "ErrorCode (0x000001c4)" > /dev/null; then echo $R exit 1 fi # Get public key of handle tpm2_readpublic --object-context=${HANDLE} --output=mykey.pem --format=pem # Release persistent HANDLE tpm2_evictcontrol --hierarchy=o --object-context=${HANDLE} R="$(openssl pkeyutl -pubin -inkey mykey.pem -verify -in mydata.txt -sigfile mysig || true)" if ! echo $R | grep "Signature Verified Successfully" >/dev/null; then echo $R exit 1 fi 0707010000002A000081ED00000000000000000000000164643FF8000006D6000000000000000000000000000000000000003C00000000tpm2-tss-engine-1684291576.28be674/test/ecdsa-restricted.sh#!/bin/bash set -eufx # Generate 2k + a bit of data dd if=/dev/zero of=mydata.txt count=4 bs=512 status=none echo -n "abcde12345abcde12345">>mydata.txt # Create a Primary key pair echo "Generating primary key" PARENT_CTX=primary_owner_key.ctx tpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=ecc \ --key-context=${PARENT_CTX} tpm2_flushcontext --transient-object # Create an ECDSA key pair echo "Generating ECDSA key pair" TPM_ECDSA_PUBKEY=ecdsakey.pub TPM_ECDSA_KEY=ecdsakey tpm2_create --parent-context=${PARENT_CTX} \ --hash-algorithm=sha256 --key-algorithm=ecc256:ecdsa-sha256:null \ --public=${TPM_ECDSA_PUBKEY} --private=${TPM_ECDSA_KEY} \ --attributes=sign\|restricted\|fixedtpm\|fixedparent\|sensitivedataorigin\|userwithauth\|noda tpm2_flushcontext --transient-object # Load Key to persistent handle ECDSA_CTX=ecdsakey.ctx tpm2_load --parent-context=${PARENT_CTX} \ --public=${TPM_ECDSA_PUBKEY} --private=${TPM_ECDSA_KEY} \ --key-context=${ECDSA_CTX} tpm2_flushcontext --transient-object HANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${ECDSA_CTX} | cut -d ' ' -f 2 | head -n 1) tpm2_flushcontext --transient-object tpm2_readpublic --object-context=${HANDLE} # Digest & sign Data openssl dgst -engine tpm2tss -keyform engine -sha256 -sign ${HANDLE} -out mysig mydata.txt # Get public key of handle tpm2_readpublic --object-context=${HANDLE} --output=mykey.pem --format=pem # Release persistent HANDLE tpm2_evictcontrol --hierarchy=o --object-context=${HANDLE} R="$(openssl dgst -verify mykey.pem -sha256 -signature mysig mydata.txt || true)" if ! echo $R | grep "Verified OK" >/dev/null; then echo $R exit 1 fi 0707010000002B000081ED00000000000000000000000164643FF8000001D1000000000000000000000000000000000000003100000000tpm2-tss-engine-1684291576.28be674/test/ecdsa.sh#!/bin/bash set -eufx echo -n "abcde12345abcde12345">mydata tpm2tss-genkey -a ecdsa -c nist_p256 -p abc mykey echo "abc" | openssl pkeyutl -keyform engine -engine tpm2tss -inkey mykey -sign -in mydata -out mysig -passin stdin R="$(echo "abc" | openssl pkeyutl -keyform engine -engine tpm2tss -inkey mykey -verify -in mydata -sigfile mysig -passin stdin || true)" if ! echo $R | grep "Signature Verified Successfully" >/dev/null; then echo $R exit 1 fi 0707010000002C000081A400000000000000000000000164643FF800000862000000000000000000000000000000000000004700000000tpm2-tss-engine-1684291576.28be674/test/error_tpm2-tss-engine-common.c/* SPDX-License-Identifier: BSD-2 */ /******************************************************************************* * Copyright 2019, Fraunhofer SIT sponsored by Infineon Technologies AG * All rights reserved. ******************************************************************************/ #include "tpm2-tss-engine.h" #include "tpm2-tss-engine-common.h" #ifdef HAVE_EXECINFO #include <execinfo.h> #endif #include <stdio.h> #include <unistd.h> #include <setjmp.h> #include <cmocka.h> TSS2_RC __wrap_Esys_Initialize() { printf("Esys_Initialize called\n"); #ifdef HAVE_EXECINFO void* b[128]; backtrace_symbols_fd(b, backtrace(b, sizeof(b)/sizeof(b[0])), STDOUT_FILENO); #endif return -1; } void check_tpm2tss_tpm2data_readtpm(void **state) { (void)(state); int i; i = tpm2tss_tpm2data_readtpm(0, NULL); assert_int_equal(i, 0); } void check_tpm2tss_tpm2data_read(void **state) { (void)(state); int i; i = tpm2tss_tpm2data_read("", NULL); assert_int_equal(i, 0); } void check_init_tpm_parent_via_api(void **state) { (void)(state); int i; i = tpm2tss_rsa_genkey(NULL, 0, NULL, NULL, 0); assert_int_equal(i, 0); } void check_init_tpm_parent(void **state) { (void)(state); TSS2_RC r; ESYS_CONTEXT *e; ESYS_TR t; r = init_tpm_parent(&e, -1, &t); assert_int_not_equal(r, TSS2_RC_SUCCESS); } void check_init_tpm_key(void **state) { (void)(state); int i; TSS2_RC r; i = tpm2tss_rsa_genkey(NULL, 0, NULL, NULL, 0); assert_int_equal(i, 0); ESYS_CONTEXT *e; ESYS_TR t; TPM2_DATA td = { .privatetype = KEY_TYPE_HANDLE }; r = init_tpm_key(&e, &t, &td); assert_int_not_equal(r, TSS2_RC_SUCCESS); //assert_int_equal(1, 0); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(check_tpm2tss_tpm2data_readtpm), cmocka_unit_test(check_tpm2tss_tpm2data_read), cmocka_unit_test(check_init_tpm_parent_via_api), cmocka_unit_test(check_init_tpm_parent), cmocka_unit_test(check_init_tpm_key), }; return cmocka_run_group_tests(tests, NULL, NULL); } 0707010000002D000081ED00000000000000000000000164643FF800000117000000000000000000000000000000000000003400000000tpm2-tss-engine-1684291576.28be674/test/failload.sh#!/bin/bash set -eufx echo -n "abcde12345abcde12345">mykey chmod ugo-rwx mykey R="$(openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub 2>&1 || true)" echo $R if ! echo $R | grep "unable to load Private Key" >/dev/null; then exit 1 fi 0707010000002E000081ED00000000000000000000000164643FF8000000BB000000000000000000000000000000000000003500000000tpm2-tss-engine-1684291576.28be674/test/failwrite.sh#!/bin/bash set -eufx R="$(tpm2tss-genkey -a ecdsa -c nist_p256 -p abc /no/such/file/path 2>&1 || true)" echo $R if ! echo $R | grep "Error writing file" >/dev/null; then exit 1 fi 0707010000002F000081A400000000000000000000000164643FF8000002EB000000000000000000000000000000000000003700000000tpm2-tss-engine-1684291576.28be674/test/neg-handle.pem-----BEGIN TSS2 PRIVATE KEY----- MIIB8gYGZ4EFCgEDoAMBAQECBIEAAAEEggEYARYAAQALAAYEcgAAABAAEAgAAAEA AQEAyJBHMXSEunTQBWTX2uot2qnvMBEJbhuM4+/bv7Ltaz2zjFdxdSB5tLp4fJZQ AoUggU3HmF8sOGYfHTFJeNZJRFqXdB9sotNWLrWUeMXrAxdDJitGli5n87YrCTDu 6/DbJYbw1sd4/QL0sqXgzLogU7VPJhc+el5DjjimEeN6oU99zfN1HZacPTs74h0Q LPrL3BACc/lkg1q6ePREulRI/Atcy5g5hgApfjSB6kMrbOwzzkGiZVZpZBqfPaik k0SjQqNZFYejfDt99PgKQHyPHfuEVrjS788jQKvRWoPTYUQCI6iJDcp5JLk0RbqV gD68RWwhQVDCmUpq5ebP/f/47wSBwAC+ACDN2bcOjh1KxxE8YlJXVdmuwBiUL3mF hLLNWV3HWHnoAAAQ3OnaC4u9p1bOSyUPcw7fUR4UTNbqD2cSwPPMNRslR5RhoNBP +j6M2vlKP7UeSxZ/at8CZHtKWV+VS+Osy9Dn+wHdqa1YSvRCBgP1a75OI9jjQ+li I64327Vq1ZEl0LIyWdCCWrISRMcVT7JPmGhtuAS4KdHztl58JV9mntQPclW3Rp4o 5M/74zf2eaTxZOBV+OxhPR77SSQQ+w== -----END TSS2 PRIVATE KEY----- 07070100000030000081ED00000000000000000000000164643FF800000048000000000000000000000000000000000000003000000000tpm2-tss-engine-1684291576.28be674/test/rand.sh#!/bin/bash set -eufx openssl rand -engine tpm2tss -hex 10 >/dev/null 07070100000031000081ED00000000000000000000000164643FF800000220000000000000000000000000000000000000003600000000tpm2-tss-engine-1684291576.28be674/test/rsadecrypt.sh#!/bin/bash set -eufx echo -n "abcde12345abcde12345">mydata tpm2tss-genkey -a rsa -s 2048 -p abc mykey echo "abc" | openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub -passin stdin openssl pkeyutl -pubin -inkey mykey.pub -encrypt -in mydata -out mycipher rm mydata echo "abc" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -decrypt -in mycipher -out mydata -passin stdin #this is a workaround because -decrypt sometimes exits 0 falsely test "x$(cat mydata)" = "xabcde12345abcde12345" 07070100000032000081ED00000000000000000000000164643FF800000245000000000000000000000000000000000000003300000000tpm2-tss-engine-1684291576.28be674/test/rsasign.sh#!/bin/bash set -eufx echo -n "abcde12345abcde12345">mydata tpm2tss-genkey -a rsa -s 2048 -p abc mykey echo "abc" | openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub -passin stdin echo "abc" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig -passin stdin #this is a workaround because -verify allways exits 1 R="$(openssl pkeyutl -pubin -inkey mykey.pub -verify -in mydata -sigfile mysig || true)" if ! echo $R | grep "Signature Verified Successfully" >/dev/null; then echo $R exit 1 fi 07070100000033000081ED00000000000000000000000164643FF8000005FF000000000000000000000000000000000000003D00000000tpm2-tss-engine-1684291576.28be674/test/rsasign_importtpm.sh#!/bin/bash set -eufx DIR=$(mktemp -d) TPM_RSA_PUBKEY=${DIR}/rsakey.pub TPM_RSA_KEY=${DIR}/rsakey PARENT_CTX=${DIR}/primary_owner_key.ctx echo -n "abcde12345abcde12345">${DIR}/mydata tpm2_startup -c || true # Create primary key as persistent handle tpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=ecc \ --key-context=${PARENT_CTX} \ --attributes="decrypt|fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted" tpm2_flushcontext --transient-object # Create an RSA key pair echo "Generating RSA key pair" tpm2_create --key-auth=abc --parent-context=${PARENT_CTX} \ --hash-algorithm=sha256 --key-algorithm=rsa \ --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \ --attributes="sign|decrypt|fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda" tpm2_flushcontext --transient-object tpm2tss-genkey --public ${TPM_RSA_PUBKEY} --private ${TPM_RSA_KEY} --password abc ${DIR}/mykey echo "abc" | openssl rsa -engine tpm2tss -inform engine -in ${DIR}/mykey -pubout -outform pem -out ${DIR}/mykey.pub -passin stdin echo "abc" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey ${DIR}/mykey -sign -in ${DIR}/mydata -out ${DIR}/mysig -passin stdin #this is a workaround because -verify allways exits 1 R="$(openssl pkeyutl -pubin -inkey ${DIR}/mykey.pub -verify -in ${DIR}/mydata -sigfile ${DIR}/mysig || true)" if ! echo $R | grep "Signature Verified Successfully" >/dev/null; then echo $R exit 1 fi 07070100000034000081ED00000000000000000000000164643FF800000680000000000000000000000000000000000000004300000000tpm2-tss-engine-1684291576.28be674/test/rsasign_importtpmparent.sh#!/bin/bash set -eufx DIR=$(mktemp -d) TPM_RSA_PUBKEY=${DIR}/rsakey.pub TPM_RSA_KEY=${DIR}/rsakey PARENT_CTX=${DIR}/primary_owner_key.ctx echo -n "abcde12345abcde12345">${DIR}/mydata tpm2_startup -c || true # Create primary key as persistent handle tpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=rsa \ --key-context=${PARENT_CTX} tpm2_flushcontext --transient-object HANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${PARENT_CTX} | cut -d ' ' -f 2 | head -n 1) tpm2_flushcontext --transient-object # Create an RSA key pair echo "Generating RSA key pair" tpm2_create --key-auth=abc --parent-context=${HANDLE} \ --hash-algorithm=sha256 --key-algorithm=rsa \ --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \ --attributes="sign|decrypt|fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda" tpm2_flushcontext --transient-object tpm2tss-genkey --public ${TPM_RSA_PUBKEY} --private ${TPM_RSA_KEY} --password abc --parent ${HANDLE} ${DIR}/mykey echo "abc" | openssl rsa -engine tpm2tss -inform engine -in ${DIR}/mykey -pubout -outform pem -out ${DIR}/mykey.pub -passin stdin echo "abc" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey ${DIR}/mykey -sign -in ${DIR}/mydata -out ${DIR}/mysig -passin stdin # Release persistent HANDLE tpm2_evictcontrol --hierarchy=o --object-context=${HANDLE} #this is a workaround because -verify allways exits 1 R="$(openssl pkeyutl -pubin -inkey ${DIR}/mykey.pub -verify -in ${DIR}/mydata -sigfile ${DIR}/mysig || true)" if ! echo $R | grep "Signature Verified Successfully" >/dev/null; then echo $R exit 1 fi 07070100000035000081ED00000000000000000000000164643FF8000004AE000000000000000000000000000000000000003A00000000tpm2-tss-engine-1684291576.28be674/test/rsasign_parent.sh#!/bin/bash set -eufx echo -n "abcde12345abcde12345">mydata.txt # Create an Primary key pair echo "Generating primary key" PARENT_CTX=primary_owner_key.ctx tpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=rsa \ --key-context=${PARENT_CTX} tpm2_flushcontext --transient-object # Load primary key to persistent handle HANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${PARENT_CTX} | cut -d ' ' -f 2 | head -n 1) tpm2_flushcontext --transient-object # Generating a key underneath the persistent parent tpm2tss-genkey -a rsa -s 2048 -p abc -P ${HANDLE} mykey echo "abc" | openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub -passin stdin cat mykey.pub echo "abc" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata.txt -out mysig -passin stdin # Release persistent HANDLE tpm2_evictcontrol --hierarchy=o --object-context=${HANDLE} #this is a workaround because -verify allways exits 1 R="$(openssl pkeyutl -pubin -inkey mykey.pub -verify -in mydata.txt -sigfile mysig || true)" if ! echo $R | grep "Signature Verified Successfully" >/dev/null; then echo $R exit 1 fi 07070100000036000081ED00000000000000000000000164643FF8000005CC000000000000000000000000000000000000003F00000000tpm2-tss-engine-1684291576.28be674/test/rsasign_parent_pass.sh#!/bin/bash set -eufx echo -n "abcde12345abcde12345">mydata.txt # Create an Primary key pair echo "Generating primary key" PARENT_CTX=primary_owner_key.ctx tpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=rsa \ --key-context=${PARENT_CTX} --key-auth=abc tpm2_flushcontext --transient-object # Load primary key to persistent handle HANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${PARENT_CTX} | cut -d ' ' -f 2 | head -n 1) tpm2_flushcontext --transient-object # Generating a key underneath the persistent, password protected, parent tpm2tss-genkey -a rsa -s 2048 -p abc -P ${HANDLE} -W abc mykey cat > engine.conf <<EOF openssl_conf = openssl_init [openssl_init] engines = engine_section [engine_section] tpm2tss = tpm2tss_section [tpm2tss_section] SET_PARENTAUTH = abc EOF export OPENSSL_CONF=engine.conf echo "abc" | openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub -passin stdin cat mykey.pub echo "abc" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata.txt -out mysig -passin stdin # Release persistent HANDLE tpm2_evictcontrol --hierarchy=o --object-context=${HANDLE} #this is a workaround because -verify allways exits 1 R="$(openssl pkeyutl -pubin -inkey mykey.pub -verify -in mydata.txt -sigfile mysig || true)" if ! echo $R | grep "Signature Verified Successfully" >/dev/null; then echo $R exit 1 fi 07070100000037000081ED00000000000000000000000164643FF800000675000000000000000000000000000000000000003E00000000tpm2-tss-engine-1684291576.28be674/test/rsasign_persistent.sh#!/bin/bash set -eufx echo -n "abcde12345abcde12345">mydata.txt # Create an Primary key pair echo "Generating primary key" PARENT_CTX=primary_owner_key.ctx tpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=rsa \ --key-context=${PARENT_CTX} tpm2_flushcontext --transient-object # Create an RSA key pair echo "Generating RSA key pair" TPM_RSA_PUBKEY=rsakey.pub TPM_RSA_KEY=rsakey tpm2_create --key-auth=abc \ --parent-context=${PARENT_CTX} \ --hash-algorithm=sha256 --key-algorithm=rsa \ --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \ --attributes=sign\|decrypt\|fixedtpm\|fixedparent\|sensitivedataorigin\|userwithauth\|noda tpm2_flushcontext --transient-object # Load Key to persistent handle RSA_CTX=rsakey.ctx tpm2_load --parent-context=${PARENT_CTX} \ --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \ --key-context=${RSA_CTX} tpm2_flushcontext --transient-object HANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${RSA_CTX} | cut -d ' ' -f 2 | head -n 1) tpm2_flushcontext --transient-object # Signing Data echo "abc" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey ${HANDLE} -sign -in mydata.txt -out mysig -passin stdin # Get public key of handle tpm2_readpublic --object-context=${HANDLE} --output=mykey.pem --format=pem # Release persistent HANDLE tpm2_evictcontrol --hierarchy=o --object-context=${HANDLE} R="$(openssl pkeyutl -pubin -inkey mykey.pem -verify -in mydata.txt -sigfile mysig || true)" if ! echo $R | grep "Signature Verified Successfully" >/dev/null; then echo $R exit 1 fi 07070100000038000081ED00000000000000000000000164643FF8000007D8000000000000000000000000000000000000004800000000tpm2-tss-engine-1684291576.28be674/test/rsasign_persistent_emptyauth.sh#!/bin/bash set -eufx echo -n "abcde12345abcde12345">mydata.txt # Create an Primary key pair echo "Generating primary key" PARENT_CTX=primary_owner_key.ctx tpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=rsa \ --key-context=${PARENT_CTX} tpm2_flushcontext --transient-object # Create an RSA key pair echo "Generating RSA key pair" TPM_RSA_PUBKEY=rsakey.pub TPM_RSA_KEY=rsakey tpm2_create --parent-context=${PARENT_CTX} \ --hash-algorithm=sha256 --key-algorithm=rsa \ --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \ --attributes=sign\|decrypt\|fixedtpm\|fixedparent\|sensitivedataorigin\|userwithauth\|noda tpm2_flushcontext --transient-object # Load Key to persistent handle RSA_CTX=rsakey.ctx tpm2_load --parent-context=${PARENT_CTX} \ --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \ --key-context=${RSA_CTX} tpm2_flushcontext --transient-object HANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${RSA_CTX} | cut -d ' ' -f 2 | head -n 1) tpm2_flushcontext --transient-object # Signing Data #Actually signing should not require an auth value if ! openssl pkeyutl -engine tpm2tss -keyform engine -inkey ${HANDLE} -sign -in mydata.txt -out mysig -passin file:notexists; then #The expect script is only here, because tpm2-tss <2.2 had some bug, and thus us asking for passwords when none were required. expect <<EOF spawn openssl pkeyutl -engine tpm2tss -keyform engine -inkey ${HANDLE} -sign -in mydata.txt -out mysig -passin stdin expect "Enter password for user key:" send "\r\n" expect eof EOF fi # Get public key of handle tpm2_readpublic --object-context=${HANDLE} --output=mykey.pem --format=pem # Release persistent HANDLE tpm2_evictcontrol --hierarchy=o --object-context=${HANDLE} R="$(openssl pkeyutl -pubin -inkey mykey.pem -verify -in mydata.txt -sigfile mysig || true)" if ! echo $R | grep "Signature Verified Successfully" >/dev/null; then echo $R exit 1 fi 07070100000039000081ED00000000000000000000000164643FF8000006B8000000000000000000000000000000000000003E00000000tpm2-tss-engine-1684291576.28be674/test/rsasign_restricted.sh#!/bin/bash set -eufx # Generate 2k + a bit of data dd if=/dev/zero of=mydata.txt count=4 bs=512 status=none echo -n "abcde12345abcde12345">>mydata.txt # Create a Primary key pair echo "Generating primary key" PARENT_CTX=primary_owner_key.ctx tpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=rsa \ --key-context=${PARENT_CTX} tpm2_flushcontext --transient-object # Create an RSA key pair echo "Generating RSA key pair" TPM_RSA_PUBKEY=rsakey.pub TPM_RSA_KEY=rsakey tpm2_create --parent-context=${PARENT_CTX} \ --hash-algorithm=sha256 --key-algorithm=rsa:rsassa-sha256:null \ --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \ --attributes=sign\|restricted\|fixedtpm\|fixedparent\|sensitivedataorigin\|userwithauth\|noda tpm2_flushcontext --transient-object # Load Key to persistent handle RSA_CTX=rsakey.ctx tpm2_load --parent-context=${PARENT_CTX} \ --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \ --key-context=${RSA_CTX} tpm2_flushcontext --transient-object HANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${RSA_CTX} | cut -d ' ' -f 2 | head -n 1) tpm2_flushcontext --transient-object tpm2_readpublic --object-context=${HANDLE} # Digest & sign Data openssl dgst -engine tpm2tss -keyform engine -sha256 -sign ${HANDLE} -out mysig mydata.txt # Get public key of handle tpm2_readpublic --object-context=${HANDLE} --output=mykey.pem --format=pem # Release persistent HANDLE tpm2_evictcontrol --hierarchy=o --object-context=${HANDLE} R="$(openssl dgst -verify mykey.pem -sha256 -signature mysig mydata.txt || true)" if ! echo $R | grep "Verified OK" >/dev/null; then echo $R exit 1 fi 0707010000003A000081ED00000000000000000000000164643FF800000523000000000000000000000000000000000000003300000000tpm2-tss-engine-1684291576.28be674/test/sclient.sh#!/bin/bash set -eufx if openssl version | grep "OpenSSL 1.0.2" >/dev/null; then echo "OpenSSL 1.0.2 does not load the certificate; private key mismatch ???" exit 77 fi echo -en "SSL CONNECTION WORKING\n">test.html function cleanup() { kill -term $SERVER || true } openssl ecparam -genkey -name prime256v1 -noout -out ca.key echo -e "\n\n\n\n\n\n\n" | openssl req -new -x509 -batch -extensions v3_ca -key ca.key -out ca.crt echo -e "\n\n\n\n\n\n\n\n\n" | openssl req -new -newkey rsa:2048 -nodes -keyout server.key -out server.csr openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt tpm2tss-genkey -a rsa client.tpm.key echo -e "\n\n\n\n\n\n\n\n\n" | openssl req -new -key client.tpm.key -keyform engine -engine tpm2tss -out client.csr openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt openssl s_server -cert server.crt -key server.key -accept 8443 -verify 1 -CAfile ca.crt -WWW & SERVER=$! sleep 1 kill -0 $! trap "cleanup" EXIT # We have to sleep, such that the pipe stays open until the command is finished. (echo -e "GET /test.html HTTP/1.1\r\n\r\n" && sleep 1) | openssl s_client -connect 127.0.0.1:8443 -cert client.crt -key client.tpm.key -engine tpm2tss -keyform engine -CAfile ca.crt echo "SUCCESS" 0707010000003B000081ED00000000000000000000000164643FF800000AD1000000000000000000000000000000000000003B00000000tpm2-tss-engine-1684291576.28be674/test/sh_log_compiler.sh#!/bin/bash export LANG=C export OPENSSL_ENGINES="${OPENSSL_ENGINES:=$PWD/.libs}" export LD_LIBRARY_PATH="$OPENSSL_ENGINES:${LD_LIBRARY_PATH-}" export PATH="$PWD:$PATH" if [ -z "$2" ]; then # no device passed test_script="$(realpath "$1")" else test_script="$(realpath "$2")" INTEGRATION_DEVICE=$1 fi echo "Creating tpm2tss symlink" ln -fs libtpm2tss.so .libs/tpm2tss.so tmp_dir="$(mktemp --directory)" echo "Switching to temporary directory $tmp_dir" cd "$tmp_dir" if [ -z "$INTEGRATION_DEVICE" ]; then # No device is passed so the TPM simulator will be used. for simulator in 'swtpm' 'tpm_server'; do simulator_binary="$(command -v "$simulator")" && break done if [ -z "$simulator_binary" ]; then echo 'ERROR: No TPM simulator was found on PATH' exit 99 fi for attempt in $(seq 9 -1 0); do simulator_port="$(shuf --input-range 1024-65534 --head-count 1)" echo "Starting simulator on port $simulator_port" case "$simulator_binary" in *swtpm) "$simulator_binary" socket --tpm2 --server port="$simulator_port" \ --ctrl type=tcp,port="$(( simulator_port + 1 ))" \ --flags not-need-init --tpmstate dir="$tmp_dir" \ --seccomp "action=none" &;; *tpm_server) "$simulator_binary" -port "$simulator_port" &;; esac simulator_pid="$!" sleep 1 if ( ss --listening --tcp --ipv4 --processes | grep "$simulator_pid" | grep --quiet "$simulator_port" && ss --listening --tcp --ipv4 --processes | grep "$simulator_pid" | grep --quiet "$(( simulator_port + 1 ))" ) then echo "Simulator with PID $simulator_pid started successfully" break else echo "Failed to start simulator, the port might be in use" kill "$simulator_pid" if [ "$attempt" -eq 0 ]; then echo 'ERROR: Reached maximum number of tries to start simulator, giving up' exit 99 fi fi done case "$simulator_binary" in *swtpm) export TPM2TSSENGINE_TCTI="swtpm:port=$simulator_port";; *tpm_server) export TPM2TSSENGINE_TCTI="mssim:port=$simulator_port";; esac export TPM2TOOLS_TCTI="$TPM2TSSENGINE_TCTI" tpm2_startup --clear else # A physical TPM will be used for the integration test. echo "Running the test with $INTEGRATION_DEVICE" export TPM2TSSENGINE_TCTI="libtss2-tcti-device.so:$INTEGRATION_DEVICE" export TPM2TOOLS_TCTI="$TPM2TSSENGINE_TCTI" fi echo "Starting $test_script" "$test_script" test_status="$?" kill "$simulator_pid" rm -rf "$tmp_dir" exit "$test_status" 0707010000003C000081ED00000000000000000000000164643FF800000265000000000000000000000000000000000000003300000000tpm2-tss-engine-1684291576.28be674/test/sserver.sh#!/bin/bash set -eufx if openssl version | grep "OpenSSL 1.0.2" >/dev/null; then echo "OpenSSL 1.0.2 does not load the certificate; private key mismatch ???" exit 77 fi echo -n "WORKING !!!">index.html function cleanup() { kill -term $SERVER } tpm2tss-genkey -a ecdsa mykey echo -e "\n\n\n\n\n\n\n" | openssl req -new -x509 -engine tpm2tss -key mykey -keyform engine -out mykey.crt openssl s_server -www -cert mykey.crt -key mykey -keyform engine -engine tpm2tss -accept 127.0.0.1:8444 & SERVER=$! trap "cleanup" EXIT sleep 1 echo "GET index.html" | openssl s_client -connect localhost:8444 0707010000003D000081A400000000000000000000000164643FF8000002F6000000000000000000000000000000000000004100000000tpm2-tss-engine-1684291576.28be674/test/tpm2-tss-engine-common.c/* SPDX-License-Identifier: BSD-2 */ /******************************************************************************* * Copyright 2021, Erik Larsson * All rights reserved. ******************************************************************************/ #include "tpm2-tss-engine.h" #include <setjmp.h> #include <cmocka.h> void check_tpm2tss_tpm2data_read(void **state) { (void)(state); TPM2_DATA *tpm2Data = NULL; int rc; rc = tpm2tss_tpm2data_read(NEG_HANDLE_PEM, &tpm2Data); assert_int_equal(rc, 1); assert_int_equal(tpm2Data->parent, 0x81000001); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(check_tpm2tss_tpm2data_read), }; return cmocka_run_group_tests(tests, NULL, NULL); } 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!459 blocks
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2