Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package openssl_tpm2_engine for openSUSE:Factory checked in at 2022-02-17 23:40:29 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openssl_tpm2_engine (Old) and /work/SRC/openSUSE:Factory/.openssl_tpm2_engine.new.1958 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openssl_tpm2_engine" Thu Feb 17 23:40:29 2022 rev:4 rq:955652 version:3.1.0 Changes: -------- --- /work/SRC/openSUSE:Factory/openssl_tpm2_engine/openssl_tpm2_engine.changes 2021-04-06 17:31:59.651273916 +0200 +++ /work/SRC/openSUSE:Factory/.openssl_tpm2_engine.new.1958/openssl_tpm2_engine.changes 2022-02-17 23:42:13.267700073 +0100 @@ -1,0 +2,8 @@ +Thu Feb 17 14:09:11 UTC 2022 - james.bottom...@hansenpartnership.com + +- Update to version 3.1.0 + * Bandaid openssl-3 support + * direct pcr policy creation options + * TPM key RFC + +------------------------------------------------------------------- Old: ---- openssl_tpm2_engine-3.0.1.tar.gz New: ---- openssl_tpm2_engine-3.1.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openssl_tpm2_engine.spec ++++++ --- /var/tmp/diff_new_pack.Q0gEIf/_old 2022-02-17 23:42:13.835700068 +0100 +++ /var/tmp/diff_new_pack.Q0gEIf/_new 2022-02-17 23:42:13.843700068 +0100 @@ -1,7 +1,7 @@ # # spec file for package openssl_tpm2_engine # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2022 SUSE LLC # Copyright (c) 2017 james.bottom...@hansenpartnership.com # # All modifications and additions to the file contributed by third parties @@ -18,7 +18,7 @@ Name: openssl_tpm2_engine -Version: 3.0.1 +Version: 3.1.0 Release: 0 Summary: OpenSSL TPM 2.0 interface engine plugin License: LGPL-2.1-only ++++++ openssl_tpm2_engine-3.0.1.tar.gz -> openssl_tpm2_engine-3.1.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/Makefile.am new/openssl_tpm2_engine-3.1.0/Makefile.am --- old/openssl_tpm2_engine-3.0.1/Makefile.am 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/Makefile.am 2022-02-17 00:15:34.000000000 +0100 @@ -9,6 +9,10 @@ CLEANFILES = $(man1_MANS) endif +if HAVE_OPENSSL3 +CFLAGS+= -DOPENSSL_API_COMPAT=0x10100000L +endif + openssl_engine_LTLIBRARIES=libtpm2.la bin_PROGRAMS=create_tpm2_key load_tpm2_key seal_tpm2_data unseal_tpm2_data openssl_enginedir=@enginesdir@ @@ -41,4 +45,4 @@ install-data-hook: cd $(DESTDIR)$(openssl_enginedir) && $(LN_S) -f libtpm2@SHREXT@ tpm2@SHREXT@ -SUBDIRS = tests +SUBDIRS = tests doc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/configure.ac new/openssl_tpm2_engine-3.1.0/configure.ac --- old/openssl_tpm2_engine-3.0.1/configure.ac 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/configure.ac 2022-02-17 00:15:34.000000000 +0100 @@ -2,7 +2,7 @@ # configure.in for the OpenSSL TPM engine project # -AC_INIT(openssl-tpm2-engine, 3.0.1, <openssl-tpm2-eng...@groups.io>) +AC_INIT(openssl-tpm2-engine, 3.1.0, <openssl-tpm2-eng...@groups.io>) AM_INIT_AUTOMAKE([foreign 1.6.3]) AC_CANONICAL_HOST AM_CONDITIONAL(NATIVE_BUILD, test "x$cross_compiling" = "xno") @@ -50,6 +50,11 @@ AC_SUBST(OPENSSL_INCLUDE_DIR)]) AC_LANG(C) + +PKG_CHECK_MODULES([DEPS], [libcrypto >= 3.0.0], + [ac_have_openssl3=1], + [PKG_CHECK_MODULES([DEPS], [libcrypto])]) + AC_ARG_WITH( [enginesdir], [AC_HELP_STRING([--with-enginesdir], [OpenSSL engines directory])], @@ -95,6 +100,8 @@ ]) AM_CONDITIONAL(HAVE_IBM_TSS, test "$tsslibs" = "IBM") +AM_CONDITIONAL(HAVE_OPENSSL3, test "$ac_have_openssl3" = "1") + AC_DISABLE_STATIC AC_PROG_CC_STDC AM_PROG_CC_C_O @@ -128,6 +135,8 @@ AC_PATH_PROG(TPMSERVER, tpm_server,,/bin:/usr/bin:/usr/lib/ibmtss:/usr/libexec/ibmtss) AC_PATH_PROG(SWTPM, swtpm,,/bin:/usr/bin:/usr/lib/ibmtss:/usr/libexec/ibmtss) AC_PATH_PROG(SWTPM_IOCTL, swtpm_ioctl,,/bin:/usr/bin:/usr/lib/ibmtss:/usr/libexec/ibmtss) +AC_CHECK_PROG(XML2RFC, xml2rfc, xml2rfc) +AM_CONDITIONAL(HAVE_XML2RFC, test -n "${XML2RFC}") CFLAGS="$CFLAGS -Wall" SHREXT=$shrext_cmds AC_SUBST(CFLAGS) @@ -147,7 +156,7 @@ AC_SUBST(testtpm) -AC_OUTPUT([Makefile tests/Makefile]) +AC_OUTPUT([Makefile tests/Makefile doc/Makefile]) cat <<EOF diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/create_tpm2_key.1.in new/openssl_tpm2_engine-3.1.0/create_tpm2_key.1.in --- old/openssl_tpm2_engine-3.0.1/create_tpm2_key.1.in 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/create_tpm2_key.1.in 2022-02-17 00:15:34.000000000 +0100 @@ -31,6 +31,20 @@ $ echo 0000016b >> policy.txt +[PCR Values] + +The PCR values are specified as + + <bank>:<list> + +Where <bank> is any supported PCR hash bank and list specifies the +PCRs to lock the key to as both comma separated individual values as +well as comma separated ranges. So + + sha256:1,3 means PCRs 1 and 3 in the sha256 bank + + sha512:1,3-5 means PCRs 1,3,4 and 5 in the sha512 bank + [examples] Create a self-signed cert using the TPM engine: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/create_tpm2_key.c new/openssl_tpm2_engine-3.1.0/create_tpm2_key.c --- old/openssl_tpm2_engine-3.0.1/create_tpm2_key.c 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/create_tpm2_key.c 2022-02-17 00:15:34.000000000 +0100 @@ -36,6 +36,7 @@ {"key-size", 1, 0, 's'}, {"name-scheme", 1, 0, 'n'}, {"parent-handle", 1, 0, 'p'}, + {"pcr-lock", 1, 0, 'x'}, {"wrap", 1, 0, 'w'}, {"version", 0, 0, 'v'}, {"password", 1, 0, 'k'}, @@ -94,6 +95,9 @@ " may not be used for general signing or\n" " decryption but may be the parent of other\n" " keys (i.e. it is a storage key)\n" + "\t-x, --pcr-lock <pcrs> Lock the created key to the specified PCRs\n" + " By current value. See PCR VALUES for\n" + " details about formatting\n" "\n" "Report bugs to " PACKAGE_BUGREPORT "\n", argv0); @@ -817,6 +821,10 @@ ENCRYPTED_SECRET_2B secret, *enc_secret = NULL; int restricted = 0; char *parent_str = NULL; + TPML_PCR_SELECTION pcr_lock; + int has_policy = 0; + + pcr_lock.count = 0; OpenSSL_add_all_digests(); /* may be needed to decrypt the key */ @@ -824,7 +832,7 @@ while (1) { option_index = 0; - c = getopt_long(argc, argv, "n:s:ab:p:hw:vk:re:ldc:i:", + c = getopt_long(argc, argv, "n:s:ab:p:hw:vk:re:ldc:i:x:", long_options, &option_index); if (c == -1) break; @@ -899,6 +907,9 @@ case 'i': import = optarg; break; + case 'x': + tpm2_get_pcr_lock(&pcr_lock, optarg); + break; case OPT_DEPRECATED: version = 0; break; @@ -944,11 +955,24 @@ exit(1); } + if (pcr_lock.count !=0 && policyFilename) { + fprintf(stderr, "cannot specify both policy file and pcr lock\n"); + exit(1); + } + + if (pcr_lock.count != 0 && import) { + fprintf(stderr, "cannot specify pcr lock and import because pcrs may not be correct\n"); + exit(1); + } + + if (pcr_lock.count != 0 || policyFilename) + has_policy = 1; + digest.hashAlg = name_alg; sizeInBytes = TSS_GetDigestSize(digest.hashAlg); memset((uint8_t *)&digest.digest, 0, sizeInBytes); - if (policyFilename) { + if (has_policy) { sk = sk_TSSOPTPOLICY_new_null(); if (!sk) { rc = NOT_TPM_ERROR; @@ -956,10 +980,11 @@ goto out_err; } - rc = tpm2_parse_policy_file(policyFilename, sk, auth, &digest); - if (rc) { + if (policyFilename) { + rc = tpm2_parse_policy_file(policyFilename, sk, auth, &digest); reason = "parse_policy_file"; - goto out_free_policy; + if (rc) + goto out_free_policy; } } @@ -975,6 +1000,8 @@ goto out_free_auth; } } + if (has_policy && !policyFilename) + tpm2_add_auth_policy(sk, &digest); } if (import) { @@ -982,6 +1009,8 @@ EVP_PKEY *pkey = openssl_read_key(wrap); TPMT_SENSITIVE s; + rc = NOT_TPM_ERROR; + if (parent_str) { parent = tpm2_get_parent_ext(parent_str); if (parent == 0) { @@ -996,8 +1025,6 @@ pub = &objectPublic; priv = &outPrivate; - rc = NOT_TPM_ERROR; - if (!p_pkey || !pkey) { reason = "read openssl key"; goto out_err; @@ -1014,7 +1041,7 @@ reason = "openssl_to_tpm_public"; goto out_err; } - if (policyFilename) { + if (has_policy) { VAL(pub->publicArea.objectAttributes) &= ~TPMA_OBJECT_USERWITHAUTH; rc = TSS_TPM2B_Create( @@ -1059,6 +1086,15 @@ goto out_free_auth; } + if (pcr_lock.count != 0) { + rc = tpm2_pcr_lock_policy(tssContext, &pcr_lock, + sk, &digest); + if (rc) { + reason = "create pcr policy"; + goto out_free_auth; + } + } + if (parent_str) { parent = tpm2_get_parent(tssContext, parent_str); if (parent == 0) { @@ -1111,7 +1147,7 @@ goto out_flush; } - if (policyFilename) { + if (has_policy) { VAL(objectPublic.publicArea.objectAttributes) &= ~TPMA_OBJECT_USERWITHAUTH; rc = TSS_TPM2B_Create( @@ -1171,7 +1207,7 @@ tpm2_public_template_ecc(&objectPublic.publicArea, ecc); } - if (policyFilename) { + if (has_policy) { VAL(objectPublic.publicArea.objectAttributes) &= ~TPMA_OBJECT_USERWITHAUTH; rc = TSS_TPM2B_Create( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/doc/Makefile.am new/openssl_tpm2_engine-3.1.0/doc/Makefile.am --- old/openssl_tpm2_engine-3.0.1/doc/Makefile.am 1970-01-01 01:00:00.000000000 +0100 +++ new/openssl_tpm2_engine-3.1.0/doc/Makefile.am 2022-02-17 00:15:34.000000000 +0100 @@ -0,0 +1,15 @@ +XML2RFC_TARGETS = draft-bottomley-tpm2-keys.txt \ + draft-bottomley-tpm2-keys.html + +if HAVE_XML2RFC +all: $(XML2RFC_TARGETS) + +clean-local: + rm -fr $(XML2RFC_TARGETS) +endif + +$(builddir)/%.txt: $(srcdir)/%.xml + $(XML2RFC) --text -o $@ $< + +$(builddir)/%.html: $(srcdir)/%.xml + $(XML2RFC) --html -o $@ $< diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/doc/draft-bottomley-tpm2-keys.xml new/openssl_tpm2_engine-3.1.0/doc/draft-bottomley-tpm2-keys.xml --- old/openssl_tpm2_engine-3.0.1/doc/draft-bottomley-tpm2-keys.xml 1970-01-01 01:00:00.000000000 +0100 +++ new/openssl_tpm2_engine-3.1.0/doc/draft-bottomley-tpm2-keys.xml 2022-02-17 00:15:34.000000000 +0100 @@ -0,0 +1,465 @@ +<?xml version="1.0"?> +<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [ +<!-- One method to get references from the online citation libraries. +There has to be one entity for each item to be referenced. +An alternate method (rfc include) is described in the references. +--> +<!ENTITY RFC2119 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.2119.xml"> +<!ENTITY RFC8017 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.8017.xml"> +]> +<?rfc toc="yes" ?> +<rfc ipr="trust200902" category="info" docName="draft-bottomley-tpm-keys-00"> + <front> + <title abbrev="TPM 2 Key Format">ASN.1 Specification for TPM 2.0 Key Files</title> + <author initials="J." surname="Bottomley" fullname="James E.J. Bottomley"> + <organization>Linux Kernel</organization> + <address> + <postal> + <street/> + <city/> + <region/> + <country>USA</country> + </postal> + <email>james.bottom...@hansenpartnership.com</email> + </address> + </author> + <date month="May" year="2021"/> + <area>Security</area> + <keyword>I-D</keyword> + <keyword>Internet-Draft</keyword> + <keyword>X.509</keyword> + <abstract> + <t> + This specification is designed to be an extension to the ASN.1 + (defined in <xref target="X.680"/>) specification of PKCS #1 + <xref target="RFC8017"/> to define the file format of private + keys that need to be loaded into a TPM 2 device to operate. + </t> + </abstract> + </front> + <middle> + <section anchor="intro" title="Introduction"> + <t> + The Security of private keys has long been a concern and the + ability of ubiquitous devices like TPMs has made it useful to + use them for secure private key storage. With the advent of + TPM 2.0, private key storage inside the TPM (acting as a token + which could be referred to by PKCS #11) has been discouraged, + and instead key files which are loaded and evicted as + necessary is the encouraged format. This standard defines an + interoperable ASN.1 representation for such key files, so that + a key created by one tool should be loadable by a different + one. + </t> + </section> + <section anchor="terms" title="Terminology"> + <t> + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL + NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in + <xref target="RFC2119"/>. + </t> + <section title="Notation"> + <dl> + <dt>ASN.1</dt> + <dd>Abstract Syntax Notation defined in + <xref target="X.680"/></dd> + <dt>DER</dt> + <dd>Distinguished Encoding Rules. Basically a defined binary + representation for ASN.1</dd> + <dt>MSO</dt> + <dd>Most Significant Octet (the highest order + byte of an integer)</dd> + <dt>PEM</dt> + <dd>Privacy enhanced Electronic Mail. An ASCII compatible + representation of DER</dd> + <dt>TCG</dt> + <dd>Trusted Computing Group</dd> + <dt>TPM</dt> + <dd>Trusted Platform Module</dd> + </dl> + </section> + </section> + <section anchor="keyrep" title="Key Representation"> + <t> + All TPM 2.0 keys consist of two binary pieces, a public part, + which can be parsed according to the TPM specification for + TPM2B_PUBLIC <xref target="TPM2.0"/> and a private part, which + is cryptographically sealed in such a way as to be only + readable on the TPM that created it. The purpose of this + specification is to specify a format by which the public and + private pieces of a TPM key can be loaded. + </t> + <t> + The design of the TPMkey ASN.1 format is that it should have a + distinguishing OID at the beginning so the DER form of the + key can be easily recognized. In PEM form, the key MUST have + "-----BEGIN TSS2 PRIVATE KEY-----" and "-----END TSS2 PRIVATE + KEY-----" as the PEM guards. All additional information that + may be needed to load the key is specified as optional + explicit elements, which can be extended by later + specifications, which is why the TPMkey is not versioned. + </t> + <section anchor="tpmkey" title="TPMkey Syntax"> + <figure><artwork> + TPMKey ::= SEQUENCE { + type OBJECT IDENTIFIER + emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL + policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL + secret [2] EXPLICIT OCTET STRING OPTIONAL + parent INTEGER + pubkey OCTET STRING + privkey OCTET STRING + } + </artwork></figure> + <t> + The fields of type TPMKey have the following meanings: + </t> + <section title="type"> + <t> + A unique OID specifying the key type. This standard + currently defines three types of keys: a loadable key, + specified by id-loadablekey, (to be loaded with + TPM2_Load), an importable key, specified by + id-importablekey, (to be loaded with TPM2_Import) and a + sealed data key, specified by id-sealedkey, (to be + extracted with TPM2_Unseal). The TCG has reserved the + following OID prefix for this: + </t> + <figure><artwork> + id-tpmkey OBJECT IDENTIFIER ::= + {joint-iso-itu-t(2) international-organizations(23) 133 10} + </artwork></figure> + <t> + And the three key types are: + </t> + <figure><artwork> + id-loadablekey OBJECT IDENTIFIER ::= + {id-tpmkey 3} + </artwork></figure> + <figure><artwork> + id-importablekey OBJECT IDENTIFIER ::= + {id-tpmkey 4} + </artwork></figure> + <figure><artwork> + id-sealedkey OBJECT IDENTIFIER ::= + {id-tpmkey 5} + </artwork></figure> + </section> + <section title="emptyAuth"> + <t> + An implementation needs to know as it formulates the + TPM2_Load/Import/Unseal command whether it must also send + down an authorization, so this parameter gives that + indication. emptyAuth MUST be true if authorization is + NOT required and MUST BE either false or absent if + authorization is required. Since this element has + three states (one representing true and two representing + false) it is RECOMMENDED that implementations emitting + TPMkey representations use absence of the tag to represent + false. However, implementations reading TPMKey MUST + be able to process all three possible states. + </t> + </section> + <section title="policy"> + <t> + This MUST be present if the TPM key has a policy hash + because it describes to the implementation how to + construct the policy. The forms of the policy statement + are described in section <xref target="policy"/>. + </t> + </section> + <section title="secret"> + <t> + This section describes the additional cryptographic + secret used to specify the outer wrapping of an + importable key. It MUST be present for key type + id-importablekey and MUST NOT be present for any other + key type. + </t> + <t> + Importable keys (designed to be processed by TPM2_Import) + MUST have an unencrypted inner wrapper (symmetricAlg MUST + be TPM_ALG_NULL and encryptionKey MUST be empty) and an + outer wrapper encrypted to the parent key using + inSymSeed. The secret parameter is the fully marshalled + TPM2B_ENCRYPTED_SECRET form of inSymSeed. + </t> + </section> + <section title="parent"> + <t> + This MUST be present for all keys and specifies the handle + of the parent key. The parent key SHOULD be either a + persistent handle (MSO 0x81) or a permanent handle (MSO + 0x40). Since volatile handle numbering can change + unexpectedly depending on key load order, the parent + SHOULD NOT be a volatile handle (MSO 0x80). The parent MUST + NOT have any other MSO. + </t> + <t> + If a permanent handle (MSO 0x40) is specified then the + implementation MUST run TPM2_CreatePrimary on the handle + using the TCG specified Elliptic Curve template for the + NIST P-256 curve and use the primary key so generated as + the parent. + </t> + </section> + <section title="pubkey"> + <t> + This MUST be present and MUST correspond to the fully + marshalled TPM2B_PUBLIC structure of the TPM Key. + </t> + </section> + <section title="privkey"> + <t> + This MUST be present and MUST correspond to the fully + marshalled TPM2B_PRIVATE structure of the TPM Key. For + importable keys, this must be the duplicate parameter that + would be input to TPM2_Import. + </t> + </section> + </section> + </section> + <section anchor="policy" title="Key Policy Specification"> + <t> + Policy is constructed on a TPM by executing a sequence of + policy statements. This specification currently only defines + a limited subset of the allowed policy statements. The policy + is specified by a hash, which the execution of the policy + statements must reach in order for the policy to be validated + (See <xref target="TPM2.0"/> Part 1 for a detailed description. + </t> + <t> + The TPMPolicy ASN.1 MUST be a sequence of policy statements + which correspond exactly to TPM policy instructions in the + order they should be executed and additionally from which the + ultimate policy hash can be constructed. + </t> + <t> + The current policy specification is strictly for AND based + policy only and may be extended at a later date with OR + policy. However, the ASN.1 for policy is formulated as CONS + elements, leaving the possibility of adding additional but + optional elements for policy statements which are not + supported by this standard (such as TPM2_PolicyAuthorize). + </t> + <section title="TPMPolicy Syntax"> + <figure><artwork> + TPMPolicy ::= SEQUENCE { + CommandCode [0] EXPLICIT INTEGER + CommandPolicy [1] EXPLICIT OCTET STRING + } + </artwork></figure> + <t> + The Fields of type TPMPolicy have the following meanings: + </t> + <section title="CommandCode"> + <t> + This is the integer representation of the TPM command code + for the policy statement. + </t> + </section> + <section title="CommandPolicy"> + <t> + This is a binary string representing a fully marshalled, + TPM ordered, command body for the TPM policy command. + Therefore to send the command, the implementation simply + marshalls the command code and appends this octet string + as the body. + </t> + <t> + Commands which have no body, such as TPM2_AuthVal, MUST be + specified as a zero length OCTET STRING + </t> + </section> + </section> + <section title="Policy Implementation Considerations"> + <t> + The policy hash for AND based policies is constructed by extension of the prior policy hash + </t> + <figure><artwork> + newHash = HASH ( oldHash || policyHash ) + </artwork></figure> + <t> + where policyHash is usually simply the hash of the fully + marshalled policy command (including the CommandCode). + However, this isn't true for TPM2_PolicyCounterTimer() so + always consult the <xref target="TPM2.0"/> specifications + for how to construct the policyHash. + </t> + <t> + The implementation should fail fast for policy problems, so + if an individual policy command returns a failure (which + usually indicates a particular policy requirement cannot be + met), that failure should be reported in as much detail as + possible and processing of the key should fail at that + point. + </t> + <section title="Authorization Policy"> + <t> + When Authorization (Passing in a password) is required, + the emptyAuth parameter MUST be absent or set to false + and additionally the TPM_CC_PolicyAuthValue MUST be + specified as the command code for one entry in the + TPMPolicy sequence. However, the implementation MAY + choose to execute either TPM2_PolicyPassword for TPM_RS_PW + or TPM2_PolicyAuthValue for HMAC based authorization + depending on whether the command being authorized is using + sessions or not. If the policy does not require an + authorization then the emptyAuth parameter MUST be set to + true. + </t> + </section> + </section> + </section> + <section anchor="implementation" title="Implementation Considerations"> + <t> + Implementations SHOULD support all TCG mandated algorithms, + but MAY omit those deemed insecure, such as the SHA1 hash. + </t> + <t> + TPM2_Import transforms the privKey into a TPM2B_PRIVATE which + can then be used as a source to TPM2_Load, making the loading + of importable keys is necessarily a two stage process, which + can be time consuming on some TPMs. Since the TPM2B_PRIVATE + structure emitted by TPM2_Import is fully secure, + Implementations SHOULD minimize the number of TPM2_Import + operations by caching the emitted TPM2B_PRIVATE. + </t> + </section> + <section anchor="security" title="Security Considerations"> + <t> + The TPM 2.0 supports a variety of algorithms, the most common + being SHA1 and SHA256 for hashing and RSA2048 and NIST P-256 + for asymmetric keys. Implementors SHOULD NOT use deprecated + algorithms, such as SHA1, for any TPM operation. In + particular, the algorithm used for the policy hash SHOULD NOT + be SHA1 and this means that SHA1 SHOULD NOT be used as the + name algorithm hash for any TPM key. + </t> + <t> + TPM 2.0 supports a session mode (TPM_RS_PW) where + authorizations are passed to the TPM in clear text over the + TPM connection. Implementations SHOULD consider the + possibility of snooping on the wire between the implementation + and the TPM, such as <xref target="TPM GENIE"/>, and SHOULD + use HMAC session authorizations as best practice for all TPM + keys. + </t> + <t> + In addition to snooping authorizations, snooping may also + occur when key material is being exchanged between the TPM and + the implementation, such as wrapping of private keys and the + sealing and unsealing operations for sealed keys. + Implementations SHOULD always use HMAC sessions with + TPMA_SESSION_DECRYPT when sensitive information is passed in + to the TPM and HMAC sessions with TPMA_SESSION_ENCRYPT when + sensitive information is received from the TPM. + </t> + <t> + The easiest way to get the TPM to wrap an external private key + is to use TPM2_Import. However, since TPMA_SESSION_DECRYPT + only protects the first parameter (which is encryptionKey), + the duplicate should use inner symmetric encryption with a + randomly generated ephemeral key, which is then presented to + the TPM via the protected encryptionKey parameter. + </t> + <t> + The TPM has a mode where it can generate private key material + internally (using TPM2_Create) such that the private part of + the key can never leave the TPM. Implementations SHOULD + support this mode but should be aware that while keys created + like this may be more secure than wrapped keys, they can also + be used only while access to the TPM that created them is + available, so implementations SHOULD also support wrapping for + keys that are expected to outlive the TPM that's using them. + Clients can then develop best practices around TPM wrapped + identity keys, possibly with TPM created sub keys, which can + only be used on the device they were wrapped for. + </t> + <t> + Since TPM keys can only be used by the specific TPM that + created them, which is usually embedded in a piece of + hardware, they are secure against exfiltration attacks. + However, consideration should be given to an attacker gaining + access to the system containing the TPM. TPM keys are most + secure when used as part of an operating system that has + guaranteed trust properties, such as secure and measured boot. + Implementations SHOULD assist users in constructing key + policies that ensure the key can be used only when the + operating system is within its trusted parameters to minimize + threats from co-located attackers. + </t> + </section> + <section anchor="IANA" title="IANA Considerations"> + <t> + None. + </t> + </section> + <section anchor="comments" title="Comments on and Enhancements to this Document"> + <t> + Comments on this document should be addressed to the author + (james.bottom...@hansenpartnership.com) but should also CC the + email lists of the two projects implementing this + specification: + </t> + <t> + The OpenSSL engine: openssl_tpm2_eng...@groups.io + </t> + <t> + The Linux Kernel: linux-integr...@vger.kernel.org + </t> + <t> + The OpenSSL TPM2 engine <xref target="OPENSSL TPM2 ENGINE"/> + is currently the only implementation of this full + specification, so enhancements should be proposed after + patches implementing the enhancement have been accepted by + openssl_tpm2_engine or another full specification + implementation. + </t> + </section> + + </middle> + <back> + <references title="Normative References"> + &RFC2119; + &RFC8017; + <reference anchor="TPM2.0" target="https://trustedcomputinggroup.org/resource/tpm-library-specification/"> + <front> + <title>TPM 2.0 Library Specification</title> + <author> + <organization>Trusted Computing Group</organization> + </author> + <date year="2013" month="March" day="15"/> + </front> + </reference> + <reference anchor="X.680" target="https://itu.int/rec/T-REC-X.680-201508-I/en"> + <front> + <title>ITU-T Recommendation X.680, + Information technology - Abstract Syntax Notation One + (ASN.1): Specification of basic notation.</title> + <author><organization>International Telecommunication Union</organization></author> + <date year="2015" month="August"/> + </front> + </reference> + </references> + <references title="Informative References"> + <reference anchor="TPM GENIE" target="https://www.nccgroup.com/globalassets/about-us/us/documents/tpm-genie.pdf"> + <front> + <title>TPM Genie: Interposer Attacks Against the Trusted + Platform Module Serial Bus</title> + <author initials="J." surname="Boone" fullname="J. Boone"> + <organization>NCC Group</organization> + </author> + <date year="2018" month="March" day="9"/> + </front> + </reference> + <reference anchor="OPENSSL TPM2 ENGINE" target="https://git.kernel.org/pub/scm/linux/kernel/git/jejb/openssl_tpm2_engine.git/"> + <front> + <title>OpenSSL TPM2 Engine</title> + <author><organization>Open Source Project</organization></author> + </front> + </reference> + </references> + </back> +</rfc> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/e_tpm2-ecc.c new/openssl_tpm2_engine-3.1.0/e_tpm2-ecc.c --- old/openssl_tpm2_engine-3.0.1/e_tpm2-ecc.c 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/e_tpm2-ecc.c 2022-02-17 00:15:34.000000000 +0100 @@ -103,7 +103,11 @@ #endif } +#if OPENSSL_VERSION_NUMBER >= 0x30000000 + EVP_PKEY_set1_EC_KEY(pkey, eck); +#else EC_KEY_free(eck); +#endif } static void tpm2_ecc_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/e_tpm2-rsa.c new/openssl_tpm2_engine-3.1.0/e_tpm2-rsa.c --- old/openssl_tpm2_engine-3.0.1/e_tpm2-rsa.c 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/e_tpm2-rsa.c 2022-02-17 00:15:34.000000000 +0100 @@ -130,8 +130,12 @@ RSA_set_ex_data(rsa, ex_app_data, data); +#if OPENSSL_VERSION_NUMBER >= 0x30000000 + EVP_PKEY_set1_RSA(pkey, rsa); +#else /* release the reference EVP_PKEY_get1_RSA obtained */ RSA_free(rsa); +#endif } static void tpm2_rsa_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/ibm-tss.h new/openssl_tpm2_engine-3.1.0/ibm-tss.h --- old/openssl_tpm2_engine-3.0.1/ibm-tss.h 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/ibm-tss.h 2022-02-17 00:15:34.000000000 +0100 @@ -487,6 +487,32 @@ return rc; } +static inline TPM_RC +tpm2_PCR_Read(TSS_CONTEXT *tssContext, TPML_PCR_SELECTION *pcrSelectionIn, + TPML_PCR_SELECTION *pcrSelectionOut, TPML_DIGEST *pcrValues) +{ + PCR_Read_In in; + PCR_Read_Out out; + TPM_RC rc; + + in.pcrSelectionIn = *pcrSelectionIn; + + rc = TSS_Execute(tssContext, + (RESPONSE_PARAMETERS *)&out, + (COMMAND_PARAMETERS *)&in, + NULL, + TPM_CC_PCR_Read, + TPM_RH_NULL, NULL, 0); + + if (rc) + return rc; + + *pcrSelectionOut = out.pcrSelectionOut; + *pcrValues = out.pcrValues; + + return rc; +} + static inline TPM_HANDLE tpm2_handle_int(TSS_CONTEXT *tssContext, TPM_HANDLE h) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/intel-tss.h new/openssl_tpm2_engine-3.1.0/intel-tss.h --- old/openssl_tpm2_engine-3.0.1/intel-tss.h 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/intel-tss.h 2022-02-17 00:15:34.000000000 +0100 @@ -151,7 +151,7 @@ \ *buffer += offset; \ *size -= offset; \ - *written = offset; \ + *written += offset; \ \ return rc; \ } @@ -179,6 +179,9 @@ TSS_CONVERT_MARSHAL(TPM2B_DIGEST, ) TSS_CONVERT_MARSHAL(TPM2B_PUBLIC, ) TSS_CONVERT_MARSHAL(TPM2B_PRIVATE, ) +TSS_CONVERT_MARSHAL(TPML_PCR_SELECTION, ) +TSS_CONVERT_MARSHAL(UINT32, *) +#define TSS_TPM_CC_Marshal TSS_UINT32_Marshal TSS_CONVERT_UNMARSHAL(TPML_PCR_SELECTION, ) TSS_CONVERT_UNMARSHAL(TPM2B_PRIVATE, ) @@ -935,6 +938,25 @@ operandB, offset, operation); } +static inline TPM_RC +tpm2_PCR_Read(TSS_CONTEXT *tssContext, TPML_PCR_SELECTION *pcrSelectionIn, + TPML_PCR_SELECTION *pcrSelectionOut, TPML_DIGEST *pcrValues) +{ + TPML_PCR_SELECTION *out; + TPML_DIGEST *val; + TPM_RC rc; + + rc = Esys_PCR_Read(tssContext, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, + pcrSelectionIn, NULL, &out, &val); + if (rc) + return rc; + + *pcrSelectionOut = *out; + *pcrValues = *val; + + return rc; +} + static inline TPM_HANDLE tpm2_handle_ext(TSS_CONTEXT *tssContext, TPM_HANDLE esysh) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/seal_tpm2_data.1.in new/openssl_tpm2_engine-3.1.0/seal_tpm2_data.1.in --- old/openssl_tpm2_engine-3.0.1/seal_tpm2_data.1.in 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/seal_tpm2_data.1.in 2022-02-17 00:15:34.000000000 +0100 @@ -7,6 +7,20 @@ TPM. Possible uses for this blob of data include as a symmetric key, which is the use in the linux kernel trusted key infrastructure. +[PCR Values] + +The PCR values are specified as + + <bank>:<list> + +Where <bank> is any supported PCR hash bank and list specifies the +PCRs to lock the key to as both comma separated individual values as +well as comma separated ranges. So + + sha256:1,3 means PCRs 1 and 3 in the sha256 bank + + sha512:1,3-5 means PCRs 1,3,4 and 5 in the sha512 bank + [examples] Create a sealed data blob to the storage parent (owner hierarchy) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/seal_tpm2_data.c new/openssl_tpm2_engine-3.1.0/seal_tpm2_data.c --- old/openssl_tpm2_engine-3.0.1/seal_tpm2_data.c 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/seal_tpm2_data.c 2022-02-17 00:15:34.000000000 +0100 @@ -27,6 +27,7 @@ {"auth-parent", 1, 0, 'b'}, {"help", 0, 0, 'h'}, {"parent-handle", 1, 0, 'p'}, + {"pcr-lock", 1, 0, 'x'}, {"version", 0, 0, 'v'}, {"password", 1, 0, 'k'}, {"da", 0, 0, 'd'}, @@ -71,6 +72,10 @@ "\t-m,--nomigrate Create a sealed data bundle that can be\n" " migrated to other systems.\n" "\t-n, --name-scheme <scheme> name algorithm to use sha1 [sha256] sha384 sha512\n" + "\t-x, --pcr-lock <pcrs> Lock the created key to the specified PCRs\n" + " By current value. See PCR VALUES for\n" + " details about formatting\n" + "\n" "\n" "Report bugs to " PACKAGE_BUGREPORT "\n", argv0); @@ -106,6 +111,10 @@ int32_t size; uint16_t pubkey_len, privkey_len; char *parent_str = NULL; + TPML_PCR_SELECTION pcr_lock; + int has_policy = 0; + + pcr_lock.count = 0; while (1) { option_index = 0; @@ -165,6 +174,9 @@ case 'm': nomigrate = 1; break; + case 'x': + tpm2_get_pcr_lock(&pcr_lock, optarg); + break; default: printf("Unknown option '%c'\n", c); usage(argv[0]); @@ -183,22 +195,32 @@ usage(argv[0]); } + if (pcr_lock.count !=0 && policyFilename) { + fprintf(stderr, "cannot specify both policy file and pcr lock\n"); + exit(1); + } + + if (pcr_lock.count != 0 || policyFilename) + has_policy = 1; + digest.hashAlg = name_alg; sizeInBytes = TSS_GetDigestSize(digest.hashAlg); memset((uint8_t *)&digest.digest, 0, sizeInBytes); - if (policyFilename) { + if (has_policy) { sk = sk_TSSOPTPOLICY_new_null(); if (!sk) { fprintf(stderr, "Failed to allocate policy stack\n"); exit(1); } - rc = tpm2_parse_policy_file(policyFilename, sk, - data_auth, &digest); - if (rc) { - reason = "parse_policy_file"; - goto out_free_policy; + if (policyFilename) { + rc = tpm2_parse_policy_file(policyFilename, sk, + data_auth, &digest); + if (rc) { + reason = "parse_policy_file"; + goto out_free_policy; + } } } @@ -215,6 +237,8 @@ goto out_free_auth; } } + if (has_policy && !policyFilename) + tpm2_add_auth_policy(sk, &digest); } dir = tpm2_set_unique_tssdir(); @@ -224,6 +248,15 @@ goto out_rmdir; } + if (pcr_lock.count != 0) { + rc = tpm2_pcr_lock_policy(tssContext, &pcr_lock, + sk, &digest); + if (rc) { + reason = "create pcr policy"; + goto out_free_auth; + } + } + if (parent_str) { parent = tpm2_get_parent(tssContext, parent_str); if (parent == 0) { @@ -245,7 +278,7 @@ tpm2_public_template_seal(p); - if (policyFilename) { + if (has_policy) { VAL(p->objectAttributes) &= ~TPMA_OBJECT_USERWITHAUTH; rc = TSS_TPM2B_Create( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/tests/check_counter_timer.sh new/openssl_tpm2_engine-3.1.0/tests/check_counter_timer.sh --- old/openssl_tpm2_engine-3.0.1/tests/check_counter_timer.sh 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/tests/check_counter_timer.sh 2022-02-17 00:15:34.000000000 +0100 @@ -27,10 +27,11 @@ # 3. encode a message using the TPM key # 4. verify the message through the public key ## +echo "policy counter timer" > plain.txt ${bindir}/create_tpm2_key key.tpm -a -k paSSW0RD -c policy.txt && \ openssl rsa -engine tpm2 -inform engine -pubin -in key.tpm -pubout -out key.pub && \ -echo "policy counter timer" | openssl rsautl -sign -passin pass:paSSW0RD -engine tpm2 -engine tpm2 -keyform engine -inkey key.tpm -out tmp.msg && \ -openssl rsautl -verify -in tmp.msg -inkey key.pub -pubin || exit 1 +openssl pkeyutl -sign -in plain.txt -passin pass:paSSW0RD -engine tpm2 -engine tpm2 -keyform engine -inkey key.tpm -out tmp.msg && \ +openssl pkeyutl -verify -in plain.txt -sigfile tmp.msg -inkey key.pub -pubin || exit 1 ## # advance the TPM clock by ten minutes and a second which should make @@ -44,7 +45,7 @@ # now the signing operation should fail ## echo "Check key failure due to counter timer policy" -echo "policy fail counter timer" | openssl rsautl -sign -passin pass:paSSW0RD -engine tpm2 -engine tpm2 -keyform engine -inkey key.tpm -out tmp.msg 2> tmp.txt && exit 1 +openssl pkeyutl -sign -in plain.txt -passin pass:paSSW0RD -engine tpm2 -engine tpm2 -keyform engine -inkey key.tpm -out tmp.msg 2> tmp.txt && exit 1 # check we got the right failure message grep "Policy Failure: Counter Timer at offset 8 is not <=" tmp.txt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/tests/check_enhanced_auth.sh new/openssl_tpm2_engine-3.1.0/tests/check_enhanced_auth.sh --- old/openssl_tpm2_engine-3.0.1/tests/check_enhanced_auth.sh 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/tests/check_enhanced_auth.sh 2022-02-17 00:15:34.000000000 +0100 @@ -19,7 +19,22 @@ ${bindir}/create_tpm2_key key.tpm -c policies/policy_bogus.txt a=0; while [ $a -lt 5 ]; do a=$[$a+1] - echo "This is a message" | openssl rsautl -sign -engine tpm2 -engine tpm2 -keyform engine -inkey key.tpm -out tmp.msg && exit 1 + echo "This is a message" | openssl pkeyutl -sign -engine tpm2 -engine tpm2 -keyform engine -inkey key.tpm -out tmp.msg && exit 1 +done + +## +# Randomize the PCR banks +## +for h in "sha1" "sha256" "sha384"; do + pcr=0; + while [ $pcr -lt 24 ]; do + tsspcrextend -ha $pcr -halg $h -ic $RANDOM + pcr=$[$pcr + 1] + done + ## + # reset PCR 16 for the fixed policy tests + ## + ${tss_pcrreset_cmd} -ha 16 done for h in "sha1" "" "sha384"; do @@ -35,10 +50,11 @@ # 2. get the corresponding public key from the engine # 3. encode a message using the TPM key # 4. verify the message through the public key + echo "This is a Message" > plain.txt ${bindir}/create_tpm2_key ${n} -a -k passw0rd key2.tpm -c policies/policy_authvalue.txt && \ openssl rsa -engine tpm2 -inform engine -passin pass:passw0rd -in key2.tpm -pubout -out key2.pub && \ - echo "This is a message" | openssl rsautl -sign -engine tpm2 -engine tpm2 -keyform engine -inkey key2.tpm -passin pass:passw0rd -out tmp.msg && \ - openssl rsautl -verify -in tmp.msg -inkey key2.pub -pubin || exit 1 + openssl pkeyutl -sign -engine tpm2 -engine tpm2 -keyform engine -inkey key2.tpm -passin pass:passw0rd -in plain.txt -out tmp.msg && \ + openssl pkeyutl -verify -in plain.txt -sigfile tmp.msg -inkey key2.pub -pubin || exit 1 ## # test is @@ -52,8 +68,8 @@ ${tss_pcrextend_cmd} -ha 16 -ic aaa ${bindir}/create_tpm2_key ${n} key2.tpm -c policies/policy_pcr${h}.txt && \ openssl rsa -engine tpm2 -inform engine -in key2.tpm -pubout -out key2.pub && \ - echo "This is a message" | openssl rsautl -sign -engine tpm2 -engine tpm2 -keyform engine -inkey key2.tpm -out tmp.msg && \ - openssl rsautl -verify -in tmp.msg -inkey key2.pub -pubin || exit 1 + openssl pkeyutl -sign -in plain.txt -engine tpm2 -engine tpm2 -keyform engine -inkey key2.tpm -out tmp.msg && \ + openssl pkeyutl -verify -in plain.txt -sigfile tmp.msg -inkey key2.pub -pubin || exit 1 ## # test is @@ -65,8 +81,8 @@ ${tss_pcrreset_cmd} -ha 16 ${bindir}/create_tpm2_key ${n} key2.tpm -c policies/policy_pcr${h}.txt openssl rsa -engine tpm2 -inform engine -in key2.tpm -pubout -out key2.pub && \ - echo "This is a message" | openssl rsautl -sign -engine tpm2 -engine tpm2 -keyform engine -inkey key2.tpm -out tmp.msg && \ - openssl rsautl -verify -in tmp.msg -inkey key2.pub -pubin + openssl pkeyutl -sign -in plain.txt -engine tpm2 -engine tpm2 -keyform engine -inkey key2.tpm -out tmp.msg && \ + openssl pkeyutl -verify -in plain.txt -sigfile tmp.msg -inkey key2.pub -pubin if [ $? -ne 1 ]; then echo "TPM key should not be accessible" exit 1 @@ -85,8 +101,8 @@ ${tss_pcrextend_cmd} -ha 16 -ic aaa ${bindir}/create_tpm2_key ${n} -a -k passw0rd key2.tpm -c policy_authvalue_pcr.txt && \ openssl rsa -engine tpm2 -inform engine -passin pass:passw0rd -in key2.tpm -pubout -out key2.pub && \ - echo "This is a message" | openssl rsautl -sign -engine tpm2 -engine tpm2 -keyform engine -inkey key2.tpm -passin pass:passw0rd -out tmp.msg && \ - openssl rsautl -verify -in tmp.msg -inkey key2.pub -pubin || exit 1 + openssl pkeyutl -sign -in plain.txt -engine tpm2 -engine tpm2 -keyform engine -inkey key2.tpm -passin pass:passw0rd -out tmp.msg && \ + openssl pkeyutl -verify -in plain.txt -sigfile tmp.msg -inkey key2.pub -pubin || exit 1 ## # test is @@ -101,6 +117,36 @@ ${tss_pcrextend_cmd} -ha 16 -ic aaa ${bindir}/create_tpm2_key ${n} -a -k passw0rd key2.tpm -c policy_pcr_authvalue.txt && \ openssl rsa -engine tpm2 -inform engine -passin pass:passw0rd -in key2.tpm -pubout -out key2.pub && \ - echo "This is a message" | openssl rsautl -sign -engine tpm2 -engine tpm2 -keyform engine -inkey key2.tpm -passin pass:passw0rd -out tmp.msg && \ - openssl rsautl -verify -in tmp.msg -inkey key2.pub -pubin || exit 1 + openssl pkeyutl -sign -in plain.txt -engine tpm2 -engine tpm2 -keyform engine -inkey key2.tpm -passin pass:passw0rd -out tmp.msg && \ + openssl pkeyutl -verify -in plain.txt -sigfile tmp.msg -inkey key2.pub -pubin || exit 1 + + ## + # test is + # 1. Create a key on a huge range of PCRs (testing multiple reads) + # 2. verify key works with undisturbed PCRs + # 3. extend non-mentioned pcr and verify key works + # 4. extend mentioned PCR and verify key fails + ## + ${bindir}/create_tpm2_key ${n} -a -k passw0rd key.tpm --pcr-lock 1,2,3-15,17-23 --pcr-lock sha1:1-4 --pcr-lock sha384:10-20 || exit 1 + openssl rsa -engine tpm2 -inform engine -passin pass:passw0rd -in key.tpm -pubout -out key.pub || exit 1 + openssl pkeyutl -sign -in plain.txt -engine tpm2 -engine tpm2 -keyform engine -inkey key.tpm -passin pass:passw0rd -out tmp.msg || exit 1 + openssl pkeyutl -verify -in plain.txt -sigfile tmp.msg -inkey key.pub -pubin || exit 1 + ${tss_pcrextend_cmd} -ha 16 -ic $RANDOM + ${tss_pcrextend_cmd} -ha 5 -halg sha1 -ic $RANDOM + ${tss_pcrextend_cmd} -ha 9 -halg sha384 -ic $RANDOM + openssl pkeyutl -sign -in plain.txt -engine tpm2 -engine tpm2 -keyform engine -inkey key.tpm -passin pass:passw0rd -out tmp.msg || exit 1 + openssl pkeyutl -verify -in plain.txt -sigfile tmp.msg -inkey key.pub -pubin || exit 1 + ${tss_pcrextend_cmd} -ha 1 -halg sha1 -ic $RANDOM + openssl pkeyutl -sign -in plain.txt -engine tpm2 -engine tpm2 -keyform engine -inkey key.tpm -passin pass:passw0rd -out tmp.msg && exit 1 + ## + # Check a smaller PCR lock with no auth + ## + ${bindir}/create_tpm2_key ${n} --pcr-lock 2,4,7,10 --pcr-lock sha1:1,3 key.tpm || exit 1 + openssl rsa -engine tpm2 -inform engine -in key.tpm -pubout -out key.pub || exit 1 + openssl pkeyutl -sign -in plain.txt -engine tpm2 -engine tpm2 -keyform engine -inkey key.tpm -out tmp.msg || exit 1 + openssl pkeyutl -verify -in plain.txt -sigfile tmp.msg -inkey key.pub -pubin || exit 1 + ${tss_pcrextend_cmd} -ha 4 -halg sha256 -ic $RANDOM + echo "This is a message" | openssl pkeyutl -sign -engine tpm2 -engine tpm2 -keyform engine -inkey key.tpm -out tmp.msg && exit 1 done + +exit 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/tests/create_ecc.sh new/openssl_tpm2_engine-3.1.0/tests/create_ecc.sh --- old/openssl_tpm2_engine-3.0.1/tests/create_ecc.sh 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/tests/create_ecc.sh 2022-02-17 00:15:34.000000000 +0100 @@ -8,7 +8,7 @@ # 2. Create a self signed x509 certificate # 3. verify the certificate for curve in $(${bindir}/create_tpm2_key --list-curves); do - if openssl ecparam -name ${curve} 2>&1 | grep 'unknown curve'; then + if openssl ecparam -name ${curve} 2>&1 | egrep '(invalid|unknown) curve'; then continue fi echo "Checking curve ${curve}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/tests/create_nonopenssl_ecc.sh new/openssl_tpm2_engine-3.1.0/tests/create_nonopenssl_ecc.sh --- old/openssl_tpm2_engine-3.0.1/tests/create_nonopenssl_ecc.sh 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/tests/create_nonopenssl_ecc.sh 2022-02-17 00:15:34.000000000 +0100 @@ -14,7 +14,7 @@ for curve in $(${bindir}/create_tpm2_key --list-curves); do - if openssl ecparam -name ${curve} 2>&1 | grep -v 'unknown curve'; then + if openssl ecparam -name ${curve} 2>&1 | egrep -v '(invalid|unknown) curve'; then continue fi echo "Checking curve ${curve}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/tests/da_check.sh new/openssl_tpm2_engine-3.1.0/tests/da_check.sh --- old/openssl_tpm2_engine-3.0.1/tests/da_check.sh 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/tests/da_check.sh 2022-02-17 00:15:34.000000000 +0100 @@ -13,7 +13,7 @@ count=1; while true; do echo "This is a message" | - openssl rsautl -sign -engine tpm2 -keyform engine -inkey key.tpm -passin pass:passwrd -out tmp.msg 2>tmp.txt + openssl pkeyutl -sign -engine tpm2 -keyform engine -inkey key.tpm -passin pass:passwrd -out tmp.msg 2>tmp.txt val=$? cat tmp.txt if [ $val -ne 1 ]; then @@ -39,7 +39,7 @@ echo "Locked out after $count tries" # try with correct password, should still be locked out echo "This is a message" | -openssl rsautl -sign -engine tpm2 -keyform engine -inkey key.tpm -passin pass:passw0rd -out tmp.msg 2>tmp.txt +openssl pkeyutl -sign -engine tpm2 -keyform engine -inkey key.tpm -passin pass:passw0rd -out tmp.msg 2>tmp.txt val=$? cat tmp.txt if [ $val -ne 1 ]; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/tests/derive_ecc.sh new/openssl_tpm2_engine-3.1.0/tests/derive_ecc.sh --- old/openssl_tpm2_engine-3.0.1/tests/derive_ecc.sh 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/tests/derive_ecc.sh 2022-02-17 00:15:34.000000000 +0100 @@ -24,7 +24,7 @@ ## for curve in $(${bindir}/create_tpm2_key --list-curves); do - if openssl ecparam -name ${curve} 2>&1 | grep 'unknown curve'; then + if openssl ecparam -name ${curve} 2>&1 | egrep '(invalid|unknown) curve'; then continue fi echo "Checking curve ${curve} explicitly named" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/tests/fail_connect.sh new/openssl_tpm2_engine-3.1.0/tests/fail_connect.sh --- old/openssl_tpm2_engine-3.0.1/tests/fail_connect.sh 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/tests/fail_connect.sh 2022-02-17 00:15:34.000000000 +0100 @@ -41,7 +41,7 @@ # conversion to public key doesn't actually contact the TPM # so this should succeed ## -openssl rsa -engine tpm2 -inform engine -in tmp.tpm -pubout -out tmp.pub 2> tmp.txt +openssl pkey -engine tpm2 -inform engine -in tmp.tpm -pubout -out tmp.pub 2> tmp.txt if [ $? -ne 0 ]; then echo "TPM key import failed with $?" cat tmp.txt @@ -51,7 +51,7 @@ # key operation does contact the TPM and should fail ## echo "This is a message" |\ -openssl rsautl -sign -engine tpm2 -keyform engine -inkey tmp.tpm -out tmp.msg 2> tmp.txt +openssl pkeyutl -sign -engine tpm2 -keyform engine -inkey tmp.tpm -out tmp.msg 2> tmp.txt if [ $? -ne 1 ]; then echo "TPM key signing failed with $?" cat tmp.txt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/tests/seal_unseal.sh new/openssl_tpm2_engine-3.1.0/tests/seal_unseal.sh --- old/openssl_tpm2_engine-3.0.1/tests/seal_unseal.sh 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/tests/seal_unseal.sh 2022-02-17 00:15:34.000000000 +0100 @@ -16,4 +16,22 @@ echo $DATA | ${bindir}/seal_tpm2_data -a -k ${AUTH} seal.tpm || exit 1; ${bindir}/unseal_tpm2_data -k ${AUTH} seal.tpm | grep -q "${DATA}" || exit 1; +## +# Check with policy +# test is +# 1. seal with a pcr lock and no auth +# 2. verify unseal +# 3. move PCR on and verify no unseal +# 4. 1-3 with auth and pcr lock +## +echo $DATA | ${bindir}/seal_tpm2_data --pcr-lock 2,16 seal.tpm || exit 1; +${bindir}/unseal_tpm2_data seal.tpm | grep -q "${DATA}" || exit 1; +tsspcrextend -ha 16 -ic $RANDOM +${bindir}/unseal_tpm2_data seal.tpm && exit 1 +echo $DATA | ${bindir}/seal_tpm2_data -a -k ${AUTH} --pcr-lock 2,16 seal.tpm || exit 1; +${bindir}/unseal_tpm2_data -k ${AUTH} seal.tpm | grep -q "${DATA}" || exit 1; +tsspcrextend -ha 16 -ic $RANDOM +${bindir}/unseal_tpm2_data -k ${AUTH} seal.tpm && exit 1 + + exit 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/tests/wrap_ecc.sh new/openssl_tpm2_engine-3.1.0/tests/wrap_ecc.sh --- old/openssl_tpm2_engine-3.0.1/tests/wrap_ecc.sh 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/tests/wrap_ecc.sh 2022-02-17 00:15:34.000000000 +0100 @@ -9,7 +9,7 @@ # 3. Create a self signed x509 certificate # 4. verify the certificate for curve in $(${bindir}/create_tpm2_key --list-curves); do - if openssl ecparam -name ${curve} 2>&1 | grep 'unknown curve'; then + if openssl ecparam -name ${curve} 2>&1 | egrep '(unknown|invalid) curve'; then continue fi echo "Checking curve ${curve}" @@ -21,7 +21,7 @@ exit 1 done for curve in $(${bindir}/create_tpm2_key --list-curves); do - if openssl ecparam -name ${curve} 2>&1 | grep 'unknown curve'; then + if openssl ecparam -name ${curve} 2>&1 | egrep '(invalid|unknown) curve'; then continue fi echo "Checking curve ${curve}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/tests/wrap_generic_ecc.sh new/openssl_tpm2_engine-3.1.0/tests/wrap_generic_ecc.sh --- old/openssl_tpm2_engine-3.0.1/tests/wrap_generic_ecc.sh 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/tests/wrap_generic_ecc.sh 2022-02-17 00:15:34.000000000 +0100 @@ -9,7 +9,7 @@ # 3. Create a self signed x509 certificate # 4. verify the certificate for curve in $(${bindir}/create_tpm2_key --list-curves); do - if openssl ecparam -name ${curve} 2>&1 | grep 'unknown curve'; then + if openssl ecparam -name ${curve} 2>&1 | egrep '(invalid|unknown) curve'; then continue fi openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:${curve} -out key.priv && \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/tpm2-common.c new/openssl_tpm2_engine-3.1.0/tpm2-common.c --- old/openssl_tpm2_engine-3.0.1/tpm2-common.c 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/tpm2-common.c 2022-02-17 00:15:34.000000000 +0100 @@ -29,6 +29,25 @@ #include "tpm2-asn.h" #include "tpm2-common.h" +static struct { + const char *hash; + TPM_ALG_ID alg; +} tpm2_hashes[] = { + { "sha1", TPM_ALG_SHA1 }, + { "sha256", TPM_ALG_SHA256 }, + { "sha384", TPM_ALG_SHA384 }, +#ifdef TPM_ALG_SHA512 + { "sha512", TPM_ALG_SHA512 }, +#endif +#ifdef TPM_ALG_SM3_256 + { "sm3", TPM_ALG_SM3_256 }, +#endif + { NULL, 0 } +}; + +#define MAX_TPM_PCRS 24 +const int MAX_TPM_PCRS_ARRAY = (MAX_TPM_PCRS + 7)/8; + struct myTPM2B { UINT16 s; BYTE *const b; @@ -1470,7 +1489,7 @@ rc = tpm2_create(&tssContext, ad->dir); if (rc) { reason="tpm2_create"; - goto import_err; + goto import_no_flush_err; } parentHandle = tpm2_handle_int(tssContext, ad->parent); @@ -1512,6 +1531,7 @@ import_err: tpm2_flush_srk(tssContext, parentHandle); + import_no_flush_err: TSS_Delete(tssContext); if (rc) { tpm2_error(rc, reason); @@ -1891,6 +1911,240 @@ sk_TSSOPTPOLICY_free(sk); } +static const char *get_hash_by_alg(TPM_ALG_ID alg) +{ + int i; + + for (i = 0; tpm2_hashes[i].hash; i++) + if (tpm2_hashes[i].alg == alg) + break; + + return tpm2_hashes[i].hash; +} + +static int add_pcrs_hash(TPML_PCR_SELECTION *pcrs, char *bank) +{ + int i; + TPM_ALG_ID alg; + + for (i = 0; tpm2_hashes[i].hash; i++) + if (strcmp(tpm2_hashes[i].hash, bank) == 0) + break; + + if (!tpm2_hashes[i].hash) { + fprintf(stderr, "unknown bank in pcrs list %s\n", bank); + exit(1); + } + alg = tpm2_hashes[i].alg; + + for (i = 0; i < pcrs->count; i++) + if (pcrs->pcrSelections[i].hash == alg) { + fprintf(stderr, "hash bank %s was already specified\n", bank); + exit(1); + } + + pcrs->pcrSelections[i].hash = alg; + pcrs->pcrSelections[i].sizeofSelect = MAX_TPM_PCRS_ARRAY; + pcrs->count++; + + return i; +} + +static void update_pcrs(TPML_PCR_SELECTION *pcrs, int bank, char *str) +{ + char *sep = strchr(str, '-'); + char *endptr; + long from, to; + int i; + + if (sep) + *sep = '\0'; + from = to = strtol(str, &endptr, 10); + if (*endptr != '\0' || from < 0 || from >= MAX_TPM_PCRS) + goto err; + + if (sep) { + str = sep + 1; + to = strtol(str, &endptr, 10); + + if (*endptr != '\0' || to < 0 || to >= MAX_TPM_PCRS) + goto err; + } + if (to < from) { + fprintf(stderr, "Incorrect PCR range specified %ld-%ld\n", + from, to); + exit(1); + } + + for (i = from; i <= to; i++) + pcrs->pcrSelections[bank].pcrSelect[i/8] |= (1 << (i%8)); + + return; + err: + fprintf(stderr, "incorrect PCR specification %s\n", str); + exit(1); +} + +void tpm2_get_pcr_lock(TPML_PCR_SELECTION *pcrs, char *arg) +{ + char *sep = strchr(arg, ':'); + char *bankstr = arg; + int bank; + + if (sep) { + *sep = '\0'; + arg = sep + 1; + } else { + bankstr = "sha256"; + } + bank = add_pcrs_hash(pcrs, bankstr); + for (sep = strchr(arg, ','); sep; arg = sep + 1, sep = strchr(arg, ',')) { + *sep = '\0'; + update_pcrs(pcrs, bank, arg); + } + update_pcrs(pcrs, bank, arg); +} + +static int hash_print(const char *hash, int start, BYTE val, int k, + TPML_DIGEST *dl, EVP_MD_CTX *ctx) +{ + int i, j; + + for (i = 0; i < 8; i++) { + TPM2B_DIGEST *d; + BYTE *db; + + if ((val & (1 << i)) == 0) + continue; + + d = &dl->digests[k++]; + db = VAL_2B_P(d, buffer); + EVP_DigestUpdate(ctx, VAL_2B_P(d, buffer), VAL_2B_P(d, size)); + printf("%s: %02d: ", hash, start + i); + for (j = 0; j < VAL_2B_P(d, size); j++) { + printf("%02x", db[j]); + } + printf("\n"); + } + return k; +} + +static void pcr_digests_process(TPML_PCR_SELECTION *in, TPML_PCR_SELECTION *out, + TPML_DIGEST *d, EVP_MD_CTX *ctx) +{ + int i, j, k = 0; + + for (i = 0; i < in->count; i++) { + const char *hash = get_hash_by_alg(out->pcrSelections[i].hash); + + for (j = 0; j < MAX_TPM_PCRS_ARRAY; j++) { + in->pcrSelections[i].pcrSelect[j] &= + ~out->pcrSelections[i].pcrSelect[j]; + + k = hash_print(hash, j * 8, + out->pcrSelections[i].pcrSelect[j], + k, d, ctx); + } + } +} + +TPM_RC tpm2_pcr_lock_policy(TSS_CONTEXT *tssContext, + TPML_PCR_SELECTION *pcrs, + STACK_OF(TSSOPTPOLICY) *sk, + TPMT_HA *digest) +{ + TSSOPTPOLICY *policy = TSSOPTPOLICY_new(); + TPM_RC rc; + BYTE buf[1024]; + UINT16 written = 0; + INT32 size = sizeof(buf); + const TPM_CC cc = TPM_CC_PolicyPCR; + DIGEST_2B pcrDigest; + BYTE *buffer = buf; + TPML_PCR_SELECTION pcrread, pcrreturn; + TPML_DIGEST pcr_digests; + EVP_MD_CTX *ctx = EVP_MD_CTX_create(); + + switch (digest->hashAlg) { + case TPM_ALG_SHA1: + EVP_DigestInit_ex(ctx, EVP_sha1(), NULL); + break; + case TPM_ALG_SHA256: + EVP_DigestInit_ex(ctx, EVP_sha256(), NULL); + break; + case TPM_ALG_SHA384: + EVP_DigestInit_ex(ctx, EVP_sha384(), NULL); + break; +#ifdef TPM_ALG_SHA512 + case TPM_ALG_SHA512: + EVP_DigestInit_ex(ctx, EVP_sha512(), NULL); + break; +#endif +#ifdef TPM_ALG_SM3_256 + case TPM_ALG_SM3_256: + EVP_DigestInit_ex(ctx, EVP_sm3(), NULL); + break; +#endif + default: + fprintf(stderr, "Unknown TPM hash algorithm 0x%x\n", + digest->hashAlg); + exit(1); + } + + pcrread = *pcrs; + + for (;;) { + rc = tpm2_PCR_Read(tssContext, &pcrread, &pcrreturn, &pcr_digests); + if (pcr_digests.count == 0 || rc != TPM_RC_SUCCESS) + break; + + pcr_digests_process(&pcrread, &pcrreturn, &pcr_digests, ctx); + } + + EVP_DigestFinal_ex(ctx, pcrDigest.buffer, NULL); + pcrDigest.size = TSS_GetDigestSize(digest->hashAlg); + EVP_MD_CTX_destroy(ctx); + + if (rc) + return rc; + + ASN1_INTEGER_set(policy->CommandCode, cc); + TSS_TPM_CC_Marshal(&cc, &written, &buffer, &size); + TSS_TPML_PCR_SELECTION_Marshal(pcrs, &written, &buffer, &size); + memcpy(buffer, pcrDigest.buffer, pcrDigest.size); + written += pcrDigest.size; + ASN1_STRING_set(policy->CommandPolicy, buf + 4, written - 4); + sk_TSSOPTPOLICY_push(sk, policy); + + TSS_Hash_Generate(digest, + TSS_GetDigestSize(digest->hashAlg), + (uint8_t *)&digest->digest, + written, buf, 0, NULL); + + return TPM_RC_SUCCESS; +} + +void tpm2_add_auth_policy(STACK_OF(TSSOPTPOLICY) *sk, TPMT_HA *digest) +{ + TSSOPTPOLICY *policy = TSSOPTPOLICY_new(); + BYTE buf[4]; + BYTE *buffer = buf; + UINT16 written = 0; + INT32 size = sizeof(buf); + const TPM_CC cc = TPM_CC_PolicyAuthValue; + + TSS_TPM_CC_Marshal(&cc, &written, &buffer, &size); + + ASN1_INTEGER_set(policy->CommandCode, cc); + ASN1_STRING_set(policy->CommandPolicy, "", 0); + sk_TSSOPTPOLICY_push(sk, policy); + + TSS_Hash_Generate(digest, + TSS_GetDigestSize(digest->hashAlg), + (uint8_t *)&digest->digest, + written, buf, 0, NULL); +} + IMPLEMENT_ASN1_FUNCTIONS(TSSOPTPOLICY) IMPLEMENT_ASN1_FUNCTIONS(TSSLOADABLE) IMPLEMENT_ASN1_FUNCTIONS(TSSPRIVKEY) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openssl_tpm2_engine-3.0.1/tpm2-common.h new/openssl_tpm2_engine-3.1.0/tpm2-common.h --- old/openssl_tpm2_engine-3.0.1/tpm2-common.h 2021-04-04 22:47:14.000000000 +0200 +++ new/openssl_tpm2_engine-3.1.0/tpm2-common.h 2022-02-17 00:15:34.000000000 +0100 @@ -88,4 +88,10 @@ STACK_OF(TSSOPTPOLICY) *sk, char *auth, TPMT_HA *digest); void tpm2_free_policy(STACK_OF(TSSOPTPOLICY) *sk); +void tpm2_get_pcr_lock(TPML_PCR_SELECTION *pcrs, char *arg); +TPM_RC tpm2_pcr_lock_policy(TSS_CONTEXT *tssContext, + TPML_PCR_SELECTION *pcrs, + STACK_OF(TSSOPTPOLICY) *sk, + TPMT_HA *digest); +void tpm2_add_auth_policy(STACK_OF(TSSOPTPOLICY) *sk, TPMT_HA *digest); #endif