!3 add upstream initial src code
From: @wangyoukang Reviewed-by: @mailofzxf Signed-off-by: @mailofzxf
This commit is contained in:
commit
28be674b78
57
CHANGELOG.md
Normal file
57
CHANGELOG.md
Normal file
@ -0,0 +1,57 @@
|
||||
# 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.
|
||||
133
CODE_OF_CONDUCT.md
Normal file
133
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,133 @@
|
||||
|
||||
# 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
|
||||
36
CONTRIBUTING.md
Normal file
36
CONTRIBUTING.md
Normal file
@ -0,0 +1,36 @@
|
||||
# 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.
|
||||
24
LICENSE
Normal file
24
LICENSE
Normal file
@ -0,0 +1,24 @@
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the 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.
|
||||
2
MAINTAINERS
Normal file
2
MAINTAINERS
Normal file
@ -0,0 +1,2 @@
|
||||
Andreas Fuchs <andreas.fuchs@sit.fraunhofer.de>
|
||||
Juergen Repp <juergen.repp@sit.fraunhofer.de> (occasionally)
|
||||
226
Makefile.am
Normal file
226
Makefile.am
Normal file
@ -0,0 +1,226 @@
|
||||
#;*****************************************************************************;
|
||||
# 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
|
||||
101
RELEASE.md
Normal file
101
RELEASE.md
Normal file
@ -0,0 +1,101 @@
|
||||
# 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.
|
||||
37
SECURITY.md
Normal file
37
SECURITY.md
Normal file
@ -0,0 +1,37 @@
|
||||
# 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.
|
||||
44
bash-completion/tpm2tss-genkey
Normal file
44
bash-completion/tpm2tss-genkey
Normal file
@ -0,0 +1,44 @@
|
||||
_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
|
||||
7
bootstrap
Executable file
7
bootstrap
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
git describe --tags --always --dirty > VERSION
|
||||
|
||||
autoreconf --install --sym
|
||||
256
configure.ac
Normal file
256
configure.ac
Normal file
@ -0,0 +1,256 @@
|
||||
#;*****************************************************************************;
|
||||
# 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
|
||||
])
|
||||
|
||||
103
include/tpm2-tss-engine.h
Normal file
103
include/tpm2-tss-engine.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*******************************************************************************
|
||||
* 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 */
|
||||
52
m4/flags.m4
Normal file
52
m4/flags.m4
Normal file
@ -0,0 +1,52 @@
|
||||
dnl 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.])]
|
||||
)]
|
||||
)]
|
||||
)
|
||||
118
man/tpm2tss-genkey.1.md
Normal file
118
man/tpm2tss-genkey.1.md
Normal file
@ -0,0 +1,118 @@
|
||||
% 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)
|
||||
|
||||
36
man/tpm2tss_ecc_genkey.3.md
Normal file
36
man/tpm2tss_ecc_genkey.3.md
Normal file
@ -0,0 +1,36 @@
|
||||
% 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)
|
||||
|
||||
39
man/tpm2tss_ecc_getappdata.3.md
Normal file
39
man/tpm2tss_ecc_getappdata.3.md
Normal file
@ -0,0 +1,39 @@
|
||||
% 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)
|
||||
|
||||
36
man/tpm2tss_ecc_makekey.3.md
Normal file
36
man/tpm2tss_ecc_makekey.3.md
Normal file
@ -0,0 +1,36 @@
|
||||
% 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)
|
||||
|
||||
36
man/tpm2tss_rsa_genkey.3.md
Normal file
36
man/tpm2tss_rsa_genkey.3.md
Normal file
@ -0,0 +1,36 @@
|
||||
% 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)
|
||||
|
||||
36
man/tpm2tss_rsa_makekey.3.md
Normal file
36
man/tpm2tss_rsa_makekey.3.md
Normal file
@ -0,0 +1,36 @@
|
||||
% 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)
|
||||
|
||||
42
man/tpm2tss_tpm2data_write.3.md
Normal file
42
man/tpm2tss_tpm2data_write.3.md
Normal file
@ -0,0 +1,42 @@
|
||||
% 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)
|
||||
|
||||
22
openssl.conf.sample
Normal file
22
openssl.conf.sample
Normal file
@ -0,0 +1,22 @@
|
||||
openssl_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
|
||||
698
src/tpm2-tss-engine-common.c
Executable file
698
src/tpm2-tss-engine-common.c
Executable file
@ -0,0 +1,698 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
199
src/tpm2-tss-engine-common.h
Executable file
199
src/tpm2-tss-engine-common.h
Executable file
@ -0,0 +1,199 @@
|
||||
/*******************************************************************************
|
||||
* 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 */
|
||||
315
src/tpm2-tss-engine-digest-sign.c
Normal file
315
src/tpm2-tss-engine-digest-sign.c
Normal file
@ -0,0 +1,315 @@
|
||||
/*******************************************************************************
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
875
src/tpm2-tss-engine-ecc.c
Normal file
875
src/tpm2-tss-engine-ecc.c
Normal file
@ -0,0 +1,875 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
187
src/tpm2-tss-engine-err.c
Normal file
187
src/tpm2-tss-engine-err.c
Normal file
@ -0,0 +1,187 @@
|
||||
/*******************************************************************************
|
||||
* 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");
|
||||
}
|
||||
133
src/tpm2-tss-engine-err.h
Normal file
133
src/tpm2-tss-engine-err.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*******************************************************************************
|
||||
* 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 */
|
||||
151
src/tpm2-tss-engine-rand.c
Normal file
151
src/tpm2-tss-engine-rand.c
Normal file
@ -0,0 +1,151 @@
|
||||
/*******************************************************************************
|
||||
* 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);
|
||||
}
|
||||
813
src/tpm2-tss-engine-rsa.c
Normal file
813
src/tpm2-tss-engine-rsa.c
Normal file
@ -0,0 +1,813 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
372
src/tpm2-tss-engine.c
Normal file
372
src/tpm2-tss-engine.c
Normal file
@ -0,0 +1,372 @@
|
||||
/*******************************************************************************
|
||||
* 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()
|
||||
415
src/tpm2tss-genkey.c
Normal file
415
src/tpm2tss-genkey.c
Normal file
@ -0,0 +1,415 @@
|
||||
/*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
62
test/ecdh.sh
Executable file
62
test/ecdh.sh
Executable file
@ -0,0 +1,62 @@
|
||||
#!/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
|
||||
15
test/ecdsa-emptyauth.sh
Executable file
15
test/ecdsa-emptyauth.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#!/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
|
||||
52
test/ecdsa-handle-flush.sh
Executable file
52
test/ecdsa-handle-flush.sh
Executable file
@ -0,0 +1,52 @@
|
||||
#!/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
|
||||
52
test/ecdsa-restricted.sh
Executable file
52
test/ecdsa-restricted.sh
Executable file
@ -0,0 +1,52 @@
|
||||
#!/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
|
||||
15
test/ecdsa.sh
Executable file
15
test/ecdsa.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#!/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
|
||||
96
test/error_tpm2-tss-engine-common.c
Normal file
96
test/error_tpm2-tss-engine-common.c
Normal file
@ -0,0 +1,96 @@
|
||||
/* 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);
|
||||
}
|
||||
12
test/failload.sh
Executable file
12
test/failload.sh
Executable file
@ -0,0 +1,12 @@
|
||||
#!/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
|
||||
9
test/failwrite.sh
Executable file
9
test/failwrite.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/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
|
||||
13
test/neg-handle.pem
Normal file
13
test/neg-handle.pem
Normal file
@ -0,0 +1,13 @@
|
||||
-----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-----
|
||||
5
test/rand.sh
Executable file
5
test/rand.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eufx
|
||||
|
||||
openssl rand -engine tpm2tss -hex 10 >/dev/null
|
||||
16
test/rsadecrypt.sh
Executable file
16
test/rsadecrypt.sh
Executable file
@ -0,0 +1,16 @@
|
||||
#!/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"
|
||||
18
test/rsasign.sh
Executable file
18
test/rsasign.sh
Executable file
@ -0,0 +1,18 @@
|
||||
#!/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
|
||||
39
test/rsasign_importtpm.sh
Executable file
39
test/rsasign_importtpm.sh
Executable file
@ -0,0 +1,39 @@
|
||||
#!/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
|
||||
43
test/rsasign_importtpmparent.sh
Executable file
43
test/rsasign_importtpmparent.sh
Executable file
@ -0,0 +1,43 @@
|
||||
#!/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
|
||||
35
test/rsasign_parent.sh
Executable file
35
test/rsasign_parent.sh
Executable file
@ -0,0 +1,35 @@
|
||||
#!/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
|
||||
50
test/rsasign_parent_pass.sh
Executable file
50
test/rsasign_parent_pass.sh
Executable file
@ -0,0 +1,50 @@
|
||||
#!/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
|
||||
48
test/rsasign_persistent.sh
Executable file
48
test/rsasign_persistent.sh
Executable file
@ -0,0 +1,48 @@
|
||||
#!/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
|
||||
57
test/rsasign_persistent_emptyauth.sh
Executable file
57
test/rsasign_persistent_emptyauth.sh
Executable file
@ -0,0 +1,57 @@
|
||||
#!/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
|
||||
52
test/rsasign_restricted.sh
Executable file
52
test/rsasign_restricted.sh
Executable file
@ -0,0 +1,52 @@
|
||||
#!/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
|
||||
43
test/sclient.sh
Executable file
43
test/sclient.sh
Executable file
@ -0,0 +1,43 @@
|
||||
#!/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"
|
||||
83
test/sh_log_compiler.sh
Executable file
83
test/sh_log_compiler.sh
Executable file
@ -0,0 +1,83 @@
|
||||
#!/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"
|
||||
27
test/sserver.sh
Executable file
27
test/sserver.sh
Executable file
@ -0,0 +1,27 @@
|
||||
#!/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
|
||||
31
test/tpm2-tss-engine-common.c
Normal file
31
test/tpm2-tss-engine-common.c
Normal file
@ -0,0 +1,31 @@
|
||||
/* 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);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user