Skip to contentSkip to conversation

TPM 2.0 trusted key rework

PATCH Superseded James Bottomley 5 participants 20 messages Nov 29, 2020 – Jan 4, 2021

Subsystems (7)

v14 of 15 Superseded Latest is v15 →

lore
Share & tools
lore

James Bottomley

author maintainer
#0 lore raw

v14 cover TPM 2.0 trusted key rework

v14: add tested by flags and fix one more 0day select problem

General cover letter minus policy bit:

This patch updates the trusted key code to export keys in the ASN.1 format used by current TPM key tools (openssl_tpm2_engine and openconnect). The current code will try to load keys containing policy, but being unable to formulate the policy commands necessary to load them, the unseal will always fail unless the policy is executed in user space and a pre-formed policy session passed in.

The key format is designed to be compatible with our two openssl engine implementations as well as with the format used by openconnect. I've added seal/unseal to my engine so I can use it for interoperability testing and I'll later use this for sealed symmetric keys via engine:

https://git.kernel.org/pub/scm/linux/kernel/git/jejb/openssl_tpm2_engine.git/

James

---

James Bottomley (5):
lib: add ASN.1 encoder
oid_registry: Add TCG defined OIDS for TPM keys
security: keys: trusted: fix TPM2 authorizations
security: keys: trusted: use ASN.1 TPM2 key format for the blobs
security: keys: trusted: Make sealed key properly interoperable

 .../security/keys/trusted-encrypted.rst       |  58 +++
 include/keys/trusted-type.h                   |   2 +
 include/linux/asn1_encoder.h                  |  32 ++
 include/linux/oid_registry.h                  |   5 +
 include/linux/tpm.h                           |   2 +
 lib/Kconfig                                   |   3 +
 lib/Makefile                                  |   1 +
 lib/asn1_encoder.c                            | 454 ++++++++++++++++++
 security/keys/Kconfig                         |   3 +
 security/keys/trusted-keys/Makefile           |   4 +-
 security/keys/trusted-keys/tpm2key.asn1       |  11 +
 security/keys/trusted-keys/trusted_tpm1.c     |  34 +-
 security/keys/trusted-keys/trusted_tpm2.c     | 266 +++++++++-
 13 files changed, 844 insertions(+), 31 deletions(-)
 create mode 100644 include/linux/asn1_encoder.h
 create mode 100644 lib/asn1_encoder.c
 create mode 100644 security/keys/trusted-keys/tpm2key.asn1
Signature · 1 line
2.26.2
author maintainer
#1 lore raw

PATCH v14 1/5 lib: add ASN.1 encoder

We have a need in the TPM2 trusted keys to return the ASN.1 form of the TPM key blob so it can be operated on by tools outside of the kernel. The specific tools are the openssl_tpm2_engine, openconnect and the Intel tpm2-tss-engine. To do that, we have to be able to read and write the same binary key format the tools use. The current ASN.1 decoder does fine for reading, but we need pieces of an ASN.1 encoder to write the key blob in binary compatible form.

For backwards compatibility, the trusted key reader code will still accept the two TPM2B quantities that it uses today, but the writer will only output the ASN.1 form.

The current implementation only encodes the ASN.1 bits we actually need.

---

v2: updated API to use indefinite length, and made symbol exports gpl
v3: add data length error handling
v4: use end_data instead of data_len pointer
v5: mention tools and space out code
v7: reverse christmas tree variable definitions and better spacing
v9: update comments, remove indefinite length, make encoder config dependent

---
 include/linux/asn1_encoder.h |  32 +++
 lib/Kconfig                  |   3 +
 lib/Makefile                 |   1 +
 lib/asn1_encoder.c           | 454 +++++++++++++++++++++++++++++++++++
 4 files changed, 490 insertions(+)
 create mode 100644 include/linux/asn1_encoder.h
 create mode 100644 lib/asn1_encoder.c
include/linux/asn1_encoder.h new file +32 -0
new file mode 100644
index 000000000000..08cd0c2ad34f
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _LINUX_ASN1_ENCODER_H
+#define _LINUX_ASN1_ENCODER_H
+
+#include <linux/types.h>
+#include <linux/asn1.h>
+#include <linux/asn1_ber_bytecode.h>
+#include <linux/bug.h>
+
+#define asn1_oid_len(oid) (sizeof(oid)/sizeof(u32))
+unsigned char *
+asn1_encode_integer(unsigned char *data, const unsigned char *end_data,
+		    s64 integer);
+unsigned char *
+asn1_encode_oid(unsigned char *data, const unsigned char *end_data,
+		u32 oid[], int oid_len);
+unsigned char *
+asn1_encode_tag(unsigned char *data, const unsigned char *end_data,
+		u32 tag, const unsigned char *string, int len);
+unsigned char *
+asn1_encode_octet_string(unsigned char *data,
+			 const unsigned char *end_data,
+			 const unsigned char *string, u32 len);
+unsigned char *
+asn1_encode_sequence(unsigned char *data, const unsigned char *end_data,
+		     const unsigned char *seq, int len);
+unsigned char *
+asn1_encode_boolean(unsigned char *data, const unsigned char *end_data,
+		    bool val);
+
+#endif
lib/Kconfig +3 -0
index b46a9fd122c8..f7d7523a26b0 100644
@@ -689,3 +689,6 @@ config GENERIC_LIB_UCMPDI2
 config PLDMFW
 	bool
 	default n
+
+config ASN1_ENCODER
+       tristate
lib/Makefile +1 -0
index ce45af50983a..05d2482cdadf 100644
@@ -281,6 +281,7 @@ obj-$(CONFIG_INTERVAL_TREE_TEST) += interval_tree_test.o
 obj-$(CONFIG_PERCPU_TEST) += percpu_test.o
 
 obj-$(CONFIG_ASN1) += asn1_decoder.o
+obj-$(CONFIG_ASN1_ENCODER) += asn1_encoder.o
 
 obj-$(CONFIG_FONT_SUPPORT) += fonts/
 
lib/asn1_encoder.c new file +454 -0

454 lines not on this page · raw message

Signature · 1 line
2.26.2
Tested-by on v14 1/5
#2 lore raw

Re: [PATCH v14 1/5] lib: add ASN.1 encoder

Quoted 8 lines · James Bottomley

We have a need in the TPM2 trusted keys to return the ASN.1 form of the TPM key blob so it can be operated on by tools outside of the kernel. The specific tools are the openssl_tpm2_engine, openconnect and the Intel tpm2-tss-engine. To do that, we have to be able to read and write the same binary key format the tools use. The current ASN.1 decoder does fine for reading, but we need pieces of an ASN.1 encoder to write the key blob in binary compatible form.

Quoted 8 lines

For backwards compatibility, the trusted key reader code will still accept the two TPM2B quantities that it uses today, but the writer will only output the ASN.1 form.

The current implementation only encodes the ASN.1 bits we actually need.

Also:

I've successfully used this multiple times already.

/Jarkko

#3 lore raw

Re: [PATCH v14 1/5] lib: add ASN.1 encoder

Quoted 15 lines · Jarkko Sakkinen
Quoted 14 lines · James Bottomley

We have a need in the TPM2 trusted keys to return the ASN.1 form of the TPM key blob so it can be operated on by tools outside of the kernel. The specific tools are the openssl_tpm2_engine, openconnect and the Intel tpm2-tss-engine. To do that, we have to be able to read and write the same binary key format the tools use. The current ASN.1 decoder does fine for reading, but we need pieces of an ASN.1 encoder to write the key blob in binary compatible form.

For backwards compatibility, the trusted key reader code will still accept the two TPM2B quantities that it uses today, but the writer will only output the ASN.1 form.

The current implementation only encodes the ASN.1 bits we actually need.

Quoted 8 lines
Quoted 2 lines

Also:

I've successfully used this multiple times already.

Hmm... Does this need ack from anyone outside of TPM space?

/Jarkko

maintainer Reviewed-by on v14 1/5
#4 lore raw

Re: [PATCH v14 1/5] lib: add ASN.1 encoder

In reply to James Bottomley

lib/asn1_encoder.c line 301

Quoted 1 line · James Bottomley
lib/asn1_encoder.c new file +1 -0
+	*(data++) = _tagn(CONT, CONS, tag);

You might want to move the _tag() and _tagn() macros into linux/asn1.h so that you don't need to include asn1_ber_bytecode.h.

But apart from that:

author maintainer
#5 lore raw

PATCH v14 2/5 oid_registry: Add TCG defined OIDS for TPM keys

In reply to James Bottomley

The TCG has defined an OID prefix "2.23.133.10.1" for the various TPM key uses. We've defined three of the available numbers:

2.23.133.10.1.3 TPM Loadable key. This is an asymmetric key (Usually
RSA2048 or Elliptic Curve) which can be imported by a TPM2_Load() operation.

2.23.133.10.1.4 TPM Importable Key. This is an asymmetric key (Usually
RSA2048 or Elliptic Curve) which can be imported by a TPM2_Import() operation.

Both loadable and importable keys are specific to a given TPM, the difference is that a loadable key is wrapped with the symmetric secret, so must have been created by the TPM itself. An importable key is wrapped with a DH shared secret, and may be created without access to the TPM provided you know the public part of the parent key.

2.23.133.10.1.5 TPM Sealed Data. This is a set of data (up to 128
bytes) which is sealed by the TPM. It usually represents a symmetric key and must be unsealed before use.

The ASN.1 binary key form starts of with this OID as the first element of a sequence, giving the binary form a unique recognizable identity marker regardless of encoding.

---

v3: correct OID_TPMImportableKey name
v7: add ack
v9: add review

---
 include/linux/oid_registry.h | 5 +++++
 1 file changed, 5 insertions(+)
include/linux/oid_registry.h +5 -0
index 4462ed2c18cd..d06988d1565e 100644
@@ -113,6 +113,11 @@ enum OID {
 	OID_SM2_with_SM3,		/* 1.2.156.10197.1.501 */
 	OID_sm3WithRSAEncryption,	/* 1.2.156.10197.1.504 */
 
+	/* TCG defined OIDS for TPM based keys */
+	OID_TPMLoadableKey,		/* 2.23.133.10.1.3 */
+	OID_TPMImportableKey,		/* 2.23.133.10.1.4 */
+	OID_TPMSealedData,		/* 2.23.133.10.1.5 */
+
 	OID__NR
 };
 
Signature · 1 line
2.26.2
maintainer
#6 lore raw

Re: [PATCH v14 2/5] oid_registry: Add TCG defined OIDS for TPM keys

Quoted 2 lines · James Bottomley

The TCG has defined an OID prefix "2.23.133.10.1" for the various TPM key uses.

Is this registered? I've checked a couple of OID registry sites (eg. www.oid-info.com) and it seems to be unknown.

David

author maintainer
#7 lore raw

Re: [PATCH v14 2/5] oid_registry: Add TCG defined OIDS for TPM keys

Quoted 7 lines · David Howells
Quoted 2 lines · James Bottomley

The TCG has defined an OID prefix "2.23.133.10.1" for the various TPM key uses.

Is this registered? I've checked a couple of OID registry sites (eg. www.oid-info.com) and it seems to be unknown.

Yes, TCG owns 2.23.133, although I still don't think Monty has published it yet:

https://lore.kernel.org/linux-integrity/26ED11907FC0F446BB0296B5357EEF0E316CDBB0@CINMBCNA02.e2k.ad.ge.com/

James

author maintainer
#8 lore raw

PATCH v14 3/5 security: keys: trusted: fix TPM2 authorizations

In reply to James Bottomley

In TPM 1.2 an authorization was a 20 byte number. The spec actually recommended you to hash variable length passwords and use the sha1 hash as the authorization. Because the spec doesn't require this hashing, the current authorization for trusted keys is a 40 digit hex number. For TPM 2.0 the spec allows the passing in of variable length passwords and passphrases directly, so we should allow that in trusted keys for ease of use. Update the 'blobauth' parameter to take this into account, so we can now use plain text passwords for the keys.

so before

keyctl add trusted kmk "new 32 blobauth=f572d396fae9206628714fb2ce00f72e94f2258fkeyhandle=81000001" @u

after we will accept both the old hex sha1 form as well as a new directly supplied password:

keyctl add trusted kmk "new 32 blobauth=hello keyhandle=81000001" @u

Since a sha1 hex code must be exactly 40 bytes long and a direct password must be 20 or less, we use the length as the discriminator for which form is input.

Note this is both and enhancement and a potential bug fix. The TPM 2.0 spec requires us to strip leading zeros, meaning empyty authorization is a zero length HMAC whereas we're currently passing in 20 bytes of zeros. A lot of TPMs simply accept this as OK, but the Microsoft TPM emulator rejects it with TPM_RC_BAD_AUTH, so this patch makes the Microsoft TPM emulator work with trusted keys.

Fixes 0fe5480303a1 ("keys, trusted: seal/unseal with TPM 2.0 chips")

---

v6: change comment, eliminate else clauses and add fixes tag
v7: fixes before signoff
v12: fix mismerge from v6 to make processing continue after blobauth
v14: add tested by

Merge with auth fix

---
 include/keys/trusted-type.h               |  1 +
 security/keys/trusted-keys/trusted_tpm1.c | 32 ++++++++++++++++++-----
 security/keys/trusted-keys/trusted_tpm2.c | 10 ++++---
 3 files changed, 33 insertions(+), 10 deletions(-)
include/keys/trusted-type.h +1 -0
index a94c03a61d8f..b2ed3481c6a0 100644
@@ -30,6 +30,7 @@ struct trusted_key_options {
 	uint16_t keytype;
 	uint32_t keyhandle;
 	unsigned char keyauth[TPM_DIGEST_SIZE];
+	uint32_t blobauth_len;
 	unsigned char blobauth[TPM_DIGEST_SIZE];
 	uint32_t pcrinfo_len;
 	unsigned char pcrinfo[MAX_PCRINFO_SIZE];
security/keys/trusted-keys/trusted_tpm1.c +26 -6
index b9fe02e5f84f..eaa2e7ca136e 100644
@@ -781,13 +781,33 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
 				return -EINVAL;
 			break;
 		case Opt_blobauth:
-			if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
-				return -EINVAL;
-			res = hex2bin(opt->blobauth, args[0].from,
-				      SHA1_DIGEST_SIZE);
-			if (res < 0)
-				return -EINVAL;
+			/*
+			 * TPM 1.2 authorizations are sha1 hashes passed in as
+			 * hex strings.  TPM 2.0 authorizations are simple
+			 * passwords (although it can take a hash as well)
+			 */
+			opt->blobauth_len = strlen(args[0].from);
+
+			if (opt->blobauth_len == 2 * TPM_DIGEST_SIZE) {
+				res = hex2bin(opt->blobauth, args[0].from,
+					      TPM_DIGEST_SIZE);
+				if (res < 0)
+					return -EINVAL;
+
+				opt->blobauth_len = TPM_DIGEST_SIZE;
+				break;
+			}
+
+			if (tpm2 && opt->blobauth_len <= sizeof(opt->blobauth)) {
+				memcpy(opt->blobauth, args[0].from,
+				       opt->blobauth_len);
+				break;
+			}
+
+			return -EINVAL;
+
 			break;
+
 		case Opt_migratable:
 			if (*args[0].from == '0')
 				pay->migratable = 0;
security/keys/trusted-keys/trusted_tpm2.c +6 -4
index 38bb33333cdf..6c6dd88d7bf6 100644
@@ -91,10 +91,12 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
 			     TPM_DIGEST_SIZE);
 
 	/* sensitive */
-	tpm_buf_append_u16(&buf, 4 + TPM_DIGEST_SIZE + payload->key_len + 1);
+	tpm_buf_append_u16(&buf, 4 + options->blobauth_len + payload->key_len + 1);
+
+	tpm_buf_append_u16(&buf, options->blobauth_len);
+	if (options->blobauth_len)
+		tpm_buf_append(&buf, options->blobauth, options->blobauth_len);
 
-	tpm_buf_append_u16(&buf, TPM_DIGEST_SIZE);
-	tpm_buf_append(&buf, options->blobauth, TPM_DIGEST_SIZE);
 	tpm_buf_append_u16(&buf, payload->key_len + 1);
 	tpm_buf_append(&buf, payload->key, payload->key_len);
 	tpm_buf_append_u8(&buf, payload->migratable);
@@ -258,7 +260,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
 			     NULL /* nonce */, 0,
 			     TPM2_SA_CONTINUE_SESSION,
 			     options->blobauth /* hmac */,
-			     TPM_DIGEST_SIZE);
+			     options->blobauth_len);
 
 	rc = tpm_send(chip, buf.data, tpm_buf_length(&buf));
 	if (rc > 0)
Signature · 1 line
2.26.2
#9 lore raw

Re: [PATCH v14 3/5] security: keys: trusted: fix TPM2 authorizations

Quoted 7 lines · James Bottomley

Note this is both and enhancement and a potential bug fix. The TPM 2.0 spec requires us to strip leading zeros, meaning empyty authorization is a zero length HMAC whereas we're currently passing in 20 bytes of zeros. A lot of TPMs simply accept this as OK, but the Microsoft TPM emulator rejects it with TPM_RC_BAD_AUTH, so this patch makes the Microsoft TPM emulator work with trusted keys.

1 - To be precise, it strips trailing zeros, but 20 bytes of zero results in an empty buffer either way.

"
Part 1 19.6.4.3 Authorization Size Convention

Trailing octets of zero are to be removed from any string before it is used as an authValue. "

2 - If you have a test case for the MS simulator, post it and I'll give it a try.

I did a quick test, power cycle to set platform auth to empty, than create primary with a parent password 20 bytes of zero, and the SW TPM accepted it.

This was a password session, not an HMAC session.

author maintainer
#10 lore raw

Re: [PATCH v14 3/5] security: keys: trusted: fix TPM2 authorizations

Quoted 19 lines · Ken Goldman
Quoted 6 lines · James Bottomley

Note this is both and enhancement and a potential bug fix. The TPM 2.0 spec requires us to strip leading zeros, meaning empyty authorization is a zero length HMAC whereas we're currently passing in 20 bytes of zeros. A lot of TPMs simply accept this as OK, but the Microsoft TPM emulator rejects it with TPM_RC_BAD_AUTH, so this patch makes the Microsoft TPM emulator work with trusted keys.

1 - To be precise, it strips trailing zeros, but 20 bytes of zero results in an empty buffer either way.

"
Part 1 19.6.4.3 Authorization Size Convention

Trailing octets of zero are to be removed from any string before it is used as an authValue.
"

Quoted 8 lines

2 - If you have a test case for the MS simulator, post it and I'll give it a try.

I did a quick test, power cycle to set platform auth to empty, than create primary with a parent password 20 bytes of zero, and the SW TPM accepted it.

This was a password session, not an HMAC session.

I reported it to Microsoft as soon as I found the problem, so, since this patch set has been languishing for years, I'd hope it would be fixed by now. It is still, however, possible there still exist TPM implementations based on the unfixed Microsoft reference platform.

James

#11 lore raw

Re: [PATCH v14 3/5] security: keys: trusted: fix TPM2 authorizations

Quoted 27 lines · James Bottomley
Quoted 26 lines · Ken Goldman
Quoted 6 lines · James Bottomley

Note this is both and enhancement and a potential bug fix. The TPM 2.0 spec requires us to strip leading zeros, meaning empyty authorization is a zero length HMAC whereas we're currently passing in 20 bytes of zeros. A lot of TPMs simply accept this as OK, but the Microsoft TPM emulator rejects it with TPM_RC_BAD_AUTH, so this patch makes the Microsoft TPM emulator work with trusted keys.

1 - To be precise, it strips trailing zeros, but 20 bytes of zero results in an empty buffer either way.

"
Part 1 19.6.4.3 Authorization Size Convention

Trailing octets of zero are to be removed from any string before it is used as an authValue.
"

2 - If you have a test case for the MS simulator, post it and I'll give it a try.

I did a quick test, power cycle to set platform auth to empty, than create primary with a parent password 20 bytes of zero, and the SW TPM accepted it.

Quoted 8 lines
Quoted 1 line

This was a password session, not an HMAC session.

I reported it to Microsoft as soon as I found the problem, so, since this patch set has been languishing for years, I'd hope it would be fixed by now. It is still, however, possible there still exist TPM implementations based on the unfixed Microsoft reference platform.

James

One year :-) A bit over but by all practical means... [*]

BTW, can you use my kernel org address for v15?

[*] https://lore.kernel.org/linux-integrity/[email protected]/

/Jarkko

author maintainer
#12 lore raw

PATCH v14 4/5 security: keys: trusted: use ASN.1 TPM2 key format for the blobs

In reply to James Bottomley

Modify the TPM2 key format blob output to export and import in the ASN.1 form for TPM2 sealed object keys. For compatibility with prior trusted keys, the importer will also accept two TPM2B quantities representing the public and private parts of the key. However, the export via keyctl pipe will only output the ASN.1 format.

The benefit of the ASN.1 format is that it's a standard and thus the exported key can be used by userspace tools (openssl_tpm2_engine, openconnect and tpm2-tss-engine). The format includes policy specifications, thus it gets us out of having to construct policy handles in userspace and the format includes the parent meaning you don't have to keep passing it in each time.

This patch only implements basic handling for the ASN.1 format, so keys with passwords but no policy.

---
v2: Updated encode API, added length checks
v5: correct export format after doing interoperability checks
v7: use prefix tpm2_key_ instead of tpmkey_ for functions
v8: resplit commit
v9: select ASN1_ENCODER
v11: add ASN.1 format description
v13: fix ASN.1 compiler dependency
v14: select OID_REGISTRY add tested by

---
 .../security/keys/trusted-encrypted.rst       |  58 +++++
 include/keys/trusted-type.h                   |   1 +
 security/keys/Kconfig                         |   3 +
 security/keys/trusted-keys/Makefile           |   4 +-
 security/keys/trusted-keys/tpm2key.asn1       |  11 +
 security/keys/trusted-keys/trusted_tpm1.c     |   2 +-
 security/keys/trusted-keys/trusted_tpm2.c     | 207 +++++++++++++++++-
 7 files changed, 278 insertions(+), 8 deletions(-)
 create mode 100644 security/keys/trusted-keys/tpm2key.asn1
Documentation/security/keys/trusted-encrypted.rst +58 -0
index 1da879a68640..549aa1308949 100644
@@ -207,3 +207,61 @@ about the usage can be found in the file
 Another new format 'enc32' has been defined in order to support encrypted keys
 with payload size of 32 bytes. This will initially be used for nvdimm security
 but may expand to other usages that require 32 bytes payload.
+
+
+TPM 2.0 ASN.1 Key Format
+------------------------
+
+The TPM 2.0 ASN.1 key format is designed to be easily recognisable,
+even in binary form (fixing a problem we had with the TPM 1.2 ASN.1
+format) and to be extensible for additions like importable keys and
+policy::
+
+    TPMKey ::= SEQUENCE {
+        type		OBJECT IDENTIFIER
+        emptyAuth	[0] EXPLICIT BOOLEAN OPTIONAL
+        parent		INTEGER
+        pubkey		OCTET STRING
+        privkey		OCTET STRING
+    }
+
+type is what distinguishes the key even in binary form since the OID
+is provided by the TCG to be unique and thus forms a recognizable
+binary pattern at offset 3 in the key.  The OIDs currently made
+available are::
+
+    2.23.133.10.1.3 TPM Loadable key.  This is an asymmetric key (Usually
+                    RSA2048 or Elliptic Curve) which can be imported by a
+                    TPM2_Load() operation.
+
+    2.23.133.10.1.4 TPM Importable Key.  This is an asymmetric key (Usually
+                    RSA2048 or Elliptic Curve) which can be imported by a
+                    TPM2_Import() operation.
+
+    2.23.133.10.1.5 TPM Sealed Data.  This is a set of data (up to 128
+                    bytes) which is sealed by the TPM.  It usually
+                    represents a symmetric key and must be unsealed before
+                    use.
+
+The trusted key code only uses the TPM Sealed Data OID.
+
+emptyAuth is true if the key has well known authorization "".  If it
+is false or not present, the key requires an explicit authorization
+phrase.  This is used by most user space consumers to decide whether
+to prompt for a password.
+
+parent represents the parent key handle, either in the 0x81 MSO space,
+like 0x81000001 for the RSA primary storage key.  Userspace programmes
+also support specifying the primary handle in the 0x40 MSO space.  If
+this happens the Elliptic Curve variant of the primary key using the
+TCG defined template will be generated on the fly into a volatile
+object and used as the parent.  The current kernel code only supports
+the 0x81 MSO form.
+
+pubkey is the binary representation of TPM2B_PRIVATE excluding the
+initial TPM2B header, which can be reconstructed from the ASN.1 octet
+string length.
+
+privkey is the binary representation of TPM2B_PUBLIC excluding the
+initial TPM2B header which can be reconstructed from the ASN.1 octed
+string length.
include/keys/trusted-type.h +1 -0
index b2ed3481c6a0..b2d87ad21714 100644
@@ -22,6 +22,7 @@ struct trusted_key_payload {
 	unsigned int key_len;
 	unsigned int blob_len;
 	unsigned char migratable;
+	unsigned char old_format;
 	unsigned char key[MAX_KEY_SIZE + 1];
 	unsigned char blob[MAX_BLOB_SIZE];
 };
security/keys/Kconfig +3 -0
index 83bc23409164..f0912692469b 100644
@@ -75,6 +75,9 @@ config TRUSTED_KEYS
 	select CRYPTO_HMAC
 	select CRYPTO_SHA1
 	select CRYPTO_HASH_INFO
+	select ASN1_ENCODER
+	select OID_REGISTRY
+	select ASN1
 	help
 	  This option provides support for creating, sealing, and unsealing
 	  keys in the kernel. Trusted keys are random number symmetric keys,
security/keys/trusted-keys/Makefile +3 -1
index 7b73cebbb378..f87c43f306d5 100644
@@ -5,4 +5,6 @@
 
 obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
 trusted-y += trusted_tpm1.o
-trusted-y += trusted_tpm2.o
+
+$(obj)/trusted_tpm2.o: $(obj)/tpm2key.asn1.h
+trusted-y += trusted_tpm2.o tpm2key.asn1.o
security/keys/trusted-keys/tpm2key.asn1 new file +11 -0
new file mode 100644
index 000000000000..3f6a9d01d1e5
@@ -0,0 +1,11 @@
+---
+--- ASN.1 for for TPM 2.0 keys
+---
+
+TPMKey ::= SEQUENCE {
+	type		OBJECT IDENTIFIER ({tpm2_key_type}),
+	emptyAuth	[0] EXPLICIT BOOLEAN OPTIONAL,
+	parent		INTEGER ({tpm2_key_parent}),
+	pubkey		OCTET STRING ({tpm2_key_pub}),
+	privkey		OCTET STRING ({tpm2_key_priv})
+	}
security/keys/trusted-keys/trusted_tpm1.c +1 -1
index eaa2e7ca136e..f235637865b9 100644
@@ -1011,7 +1011,7 @@ static int trusted_instantiate(struct key *key,
 		goto out;
 	}
 
-	if (!options->keyhandle) {
+	if (!options->keyhandle && !tpm2) {
 		ret = -EINVAL;
 		goto out;
 	}
security/keys/trusted-keys/trusted_tpm2.c +201 -6

265 lines not on this page · raw message

Signature · 1 line
2.26.2
#13 lore raw

Re: [PATCH v14 4/5] security: keys: trusted: use ASN.1 TPM2 key format for the blobs

I love your patch! Perhaps something to improve:

Hi James,

I love your patch! Perhaps something to improve:

[auto build test WARNING on integrity/next-integrity]
[also build test WARNING on linus/master v5.10-rc5 next-20201127] [cannot apply to security/next-testing dhowells-fs/fscache-next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/James-Bottomley/TPM-2-0-trusted-key-rework/20201130-063029
base:   https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git next-integrity
config: x86_64-randconfig-m001-20201130 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0

If you fix the issue, kindly add following tag as appropriate

smatch warnings:
security/keys/trusted-keys/trusted_tpm2.c:331 tpm2_seal_trusted() warn: unsigned 'payload->blob_len' is never less than zero.

vim +331 security/keys/trusted-keys/trusted_tpm2.c

217
218 /**
219 * tpm2_seal_trusted() - seal the payload of a trusted key
220 *
221 * @chip: TPM chip to use
222 * @payload: the key data in clear and encrypted form
223 * @options: authentication values and other options
224 *
225 * Return: < 0 on error and 0 on success.
226 */
227 int tpm2_seal_trusted(struct tpm_chip *chip,
228 struct trusted_key_payload *payload,
229 struct trusted_key_options *options)
230 {
231 unsigned int blob_len;
232 struct tpm_buf buf;
233 u32 hash;
234 int i;
235 int rc;
236
237 for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
238 if (options->hash == tpm2_hash_map[i].crypto_id) {
239 hash = tpm2_hash_map[i].tpm_id;
240 break;
241 }
242 }
243
244 if (i == ARRAY_SIZE(tpm2_hash_map))
245 return -EINVAL;
246
247 if (!options->keyhandle)
248 return -EINVAL;
249
250 rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
251 if (rc)
252 return rc;
253
254 tpm_buf_append_u32(&buf, options->keyhandle);
255 tpm2_buf_append_auth(&buf, TPM2_RS_PW,

   256				     NULL /* nonce */, 0,
   257				     0 /* session_attributes */,
   258				     options->keyauth /* hmac */,
   259				     TPM_DIGEST_SIZE);
   260	
   261		/* sensitive */
   262		tpm_buf_append_u16(&buf, 4 + options->blobauth_len + payload->key_len + 1);
   263	
   264		tpm_buf_append_u16(&buf, options->blobauth_len);
   265		if (options->blobauth_len)
   266			tpm_buf_append(&buf, options->blobauth, options->blobauth_len);
   267	
   268		tpm_buf_append_u16(&buf, payload->key_len + 1);
   269		tpm_buf_append(&buf, payload->key, payload->key_len);
   270		tpm_buf_append_u8(&buf, payload->migratable);
   271	
   272		/* public */
   273		tpm_buf_append_u16(&buf, 14 + options->policydigest_len);
   274		tpm_buf_append_u16(&buf, TPM_ALG_KEYEDHASH);
   275		tpm_buf_append_u16(&buf, hash);
   276	
   277		/* policy */
   278		if (options->policydigest_len) {
   279			tpm_buf_append_u32(&buf, 0);
   280			tpm_buf_append_u16(&buf, options->policydigest_len);
   281			tpm_buf_append(&buf, options->policydigest,
   282				       options->policydigest_len);
   283		} else {
   284			tpm_buf_append_u32(&buf, TPM2_OA_USER_WITH_AUTH);
   285			tpm_buf_append_u16(&buf, 0);
   286		}
   287	
   288		/* public parameters */
   289		tpm_buf_append_u16(&buf, TPM_ALG_NULL);
   290		tpm_buf_append_u16(&buf, 0);
   291	
   292		/* outside info */
   293		tpm_buf_append_u16(&buf, 0);
   294	
   295		/* creation PCR */
   296		tpm_buf_append_u32(&buf, 0);
   297	
   298		if (buf.flags & TPM_BUF_OVERFLOW) {
   299			rc = -E2BIG;
   300			goto out;
   301		}
   302	
   303		rc = tpm_send(chip, buf.data, tpm_buf_length(&buf));
   304		if (rc)
   305			goto out;
   306	
   307		blob_len = be32_to_cpup((__be32 *) &buf.data[TPM_HEADER_SIZE]);
   308		if (blob_len > MAX_BLOB_SIZE) {
   309			rc = -E2BIG;
   310			goto out;
   311		}
   312		if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 4 + blob_len) {
   313			rc = -EFAULT;
   314			goto out;
   315		}
   316	
   317		payload->blob_len =
   318			tpm2_key_encode(payload, options,
   319					&buf.data[TPM_HEADER_SIZE + 4],
   320					blob_len);
   321	
   322	out:
   323		tpm_buf_destroy(&buf);
   324	
   325		if (rc > 0) {
   326			if (tpm2_rc_value(rc) == TPM2_RC_HASH)
   327				rc = -EINVAL;
   328			else
   329				rc = -EPERM;
   330		}
 > 331		if (payload->blob_len < 0)

332 return payload->blob_len;
333
334 return rc;
335 }
336

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

author maintainer
#14 lore raw

Re: [PATCH v14 4/5] security: keys: trusted: use ASN.1 TPM2 key format for the blobs

On Mon, 2020-11-30 at 10:10 +0800, kernel test robot wrote:
[...]

Quoted 2 lines
Quoted 1 line

331 if (payload->blob_len < 0)

332 return payload->blob_len;

OK, I can rework this to use the signed version of blob len as below.

James

---

security/keys/trusted-keys/trusted_tpm2.c +8 -7
index e50563f58900..0d4c6f138b94 100644
@@ -242,7 +242,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
 		      struct trusted_key_payload *payload,
 		      struct trusted_key_options *options)
 {
-	unsigned int blob_len;
+	int blob_len = 0;
 	struct tpm_buf buf;
 	u32 hash;
 	u32 flags;
@@ -400,10 +400,9 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
 		goto out;
 	}
 
-	payload->blob_len =
-		tpm2_key_encode(payload, options,
-				&buf.data[TPM_HEADER_SIZE + 4],
-				blob_len);
+	blob_len = tpm2_key_encode(payload, options,
+				   &buf.data[TPM_HEADER_SIZE + 4],
+				   blob_len);
 
 out:
 	tpm_buf_destroy(&buf);
@@ -414,8 +413,10 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
 		else
 			rc = -EPERM;
 	}
-	if (payload->blob_len < 0)
-		return payload->blob_len;
+	if (blob_len < 0)
+		return blob_len;
+
+	payload->blob_len = blob_len;
 
 	return rc;
 }
#15 lore raw

Re: [PATCH v14 4/5] security: keys: trusted: use ASN.1 TPM2 key format for the blobs

Quoted 8 lines · James Bottomley

On Mon, 2020-11-30 at 10:10 +0800, kernel test robot wrote:
[...]

Quoted 2 lines
Quoted 1 line

331 if (payload->blob_len < 0)

332 return payload->blob_len;

OK, I can rework this to use the signed version of blob len as below.

James

Do you have the patches in a git branch somewhere with this fixed?

I can take from there and apply.

/Jarkko

#16 lore raw

Re: [PATCH v14 4/5] security: keys: trusted: use ASN.1 TPM2 key format for the blobs

Quoted 6 lines · Jarkko Sakkinen
Quoted 5 lines · James Bottomley

On Mon, 2020-11-30 at 10:10 +0800, kernel test robot wrote:
[...]

Quoted 2 lines
Quoted 1 line

331 if (payload->blob_len < 0)

332 return payload->blob_len;

Quoted 7 lines
Quoted 3 lines

OK, I can rework this to use the signed version of blob len as below.

James

Do you have the patches in a git branch somewhere with this fixed?

I can take from there and apply.

CC my korg address. Sorry for the latency, I have this LKML migration going on (MAINTAINERS is already updated). Sometimes forgot to check this inbox.

/Jarkko

author maintainer Tested-by Jarkko Sakkinen
#17 lore raw

Re: [PATCH v14 4/5] security: keys: trusted: use ASN.1 TPM2 key format for the blobs

Quoted 12 lines · Jarkko Sakkinen
Quoted 11 lines · Jarkko Sakkinen
Quoted 9 lines · James Bottomley

On Mon, 2020-11-30 at 10:10 +0800, kernel test robot wrote:
[...]

Quoted 2 lines
Quoted 1 line

331 if (payload->blob_len < 0)

332 return payload->blob_len;

OK, I can rework this to use the signed version of blob len as below.

James

Quoted 7 lines
Quoted 3 lines

Do you have the patches in a git branch somewhere with this fixed?

I can take from there and apply.

CC my korg address. Sorry for the latency, I have this LKML migration going on (MAINTAINERS is already updated). Sometimes forgot to check this inbox.

I'm preparing a v15 but this is basically the only code change.

James

---8>8>8><8<8<8---
From: James Bottomley <[email protected]>
Subject: [PATCH] security: keys: trusted: use ASN.1 TPM2 key format for the
blobs

Modify the TPM2 key format blob output to export and import in the ASN.1 form for TPM2 sealed object keys. For compatibility with prior trusted keys, the importer will also accept two TPM2B quantities representing the public and private parts of the key. However, the export via keyctl pipe will only output the ASN.1 format.

The benefit of the ASN.1 format is that it's a standard and thus the exported key can be used by userspace tools (openssl_tpm2_engine, openconnect and tpm2-tss-engine). The format includes policy specifications, thus it gets us out of having to construct policy handles in userspace and the format includes the parent meaning you don't have to keep passing it in each time.

This patch only implements basic handling for the ASN.1 format, so keys with passwords but no policy.

---
v2: Updated encode API, added length checks
v5: correct export format after doing interoperability checks
v7: use prefix tpm2_key_ instead of tpmkey_ for functions
v8: resplit commit
v9: select ASN1_ENCODER
v11: add ASN.1 format description
v13: fix ASN.1 compiler dependency
v14: select OID_REGISTRY add tested by
v15: signed blob len

---
 .../security/keys/trusted-encrypted.rst       |  58 +++++
 include/keys/trusted-type.h                   |   1 +
 security/keys/Kconfig                         |   3 +
 security/keys/trusted-keys/Makefile           |   4 +-
 security/keys/trusted-keys/tpm2key.asn1       |  11 +
 security/keys/trusted-keys/trusted_tpm1.c     |   2 +-
 security/keys/trusted-keys/trusted_tpm2.c     | 210 +++++++++++++++++-
 7 files changed, 280 insertions(+), 9 deletions(-)
 create mode 100644 security/keys/trusted-keys/tpm2key.asn1
Documentation/security/keys/trusted-encrypted.rst +58 -0
index 1da879a68640..549aa1308949 100644
@@ -207,3 +207,61 @@ about the usage can be found in the file
 Another new format 'enc32' has been defined in order to support encrypted keys
 with payload size of 32 bytes. This will initially be used for nvdimm security
 but may expand to other usages that require 32 bytes payload.
+
+
+TPM 2.0 ASN.1 Key Format
+------------------------
+
+The TPM 2.0 ASN.1 key format is designed to be easily recognisable,
+even in binary form (fixing a problem we had with the TPM 1.2 ASN.1
+format) and to be extensible for additions like importable keys and
+policy::
+
+    TPMKey ::= SEQUENCE {
+        type		OBJECT IDENTIFIER
+        emptyAuth	[0] EXPLICIT BOOLEAN OPTIONAL
+        parent		INTEGER
+        pubkey		OCTET STRING
+        privkey		OCTET STRING
+    }
+
+type is what distinguishes the key even in binary form since the OID
+is provided by the TCG to be unique and thus forms a recognizable
+binary pattern at offset 3 in the key.  The OIDs currently made
+available are::
+
+    2.23.133.10.1.3 TPM Loadable key.  This is an asymmetric key (Usually
+                    RSA2048 or Elliptic Curve) which can be imported by a
+                    TPM2_Load() operation.
+
+    2.23.133.10.1.4 TPM Importable Key.  This is an asymmetric key (Usually
+                    RSA2048 or Elliptic Curve) which can be imported by a
+                    TPM2_Import() operation.
+
+    2.23.133.10.1.5 TPM Sealed Data.  This is a set of data (up to 128
+                    bytes) which is sealed by the TPM.  It usually
+                    represents a symmetric key and must be unsealed before
+                    use.
+
+The trusted key code only uses the TPM Sealed Data OID.
+
+emptyAuth is true if the key has well known authorization "".  If it
+is false or not present, the key requires an explicit authorization
+phrase.  This is used by most user space consumers to decide whether
+to prompt for a password.
+
+parent represents the parent key handle, either in the 0x81 MSO space,
+like 0x81000001 for the RSA primary storage key.  Userspace programmes
+also support specifying the primary handle in the 0x40 MSO space.  If
+this happens the Elliptic Curve variant of the primary key using the
+TCG defined template will be generated on the fly into a volatile
+object and used as the parent.  The current kernel code only supports
+the 0x81 MSO form.
+
+pubkey is the binary representation of TPM2B_PRIVATE excluding the
+initial TPM2B header, which can be reconstructed from the ASN.1 octet
+string length.
+
+privkey is the binary representation of TPM2B_PUBLIC excluding the
+initial TPM2B header which can be reconstructed from the ASN.1 octed
+string length.
include/keys/trusted-type.h +1 -0
index b2ed3481c6a0..b2d87ad21714 100644
@@ -22,6 +22,7 @@ struct trusted_key_payload {
 	unsigned int key_len;
 	unsigned int blob_len;
 	unsigned char migratable;
+	unsigned char old_format;
 	unsigned char key[MAX_KEY_SIZE + 1];
 	unsigned char blob[MAX_BLOB_SIZE];
 };
security/keys/Kconfig +3 -0
index 83bc23409164..f0912692469b 100644
@@ -75,6 +75,9 @@ config TRUSTED_KEYS
 	select CRYPTO_HMAC
 	select CRYPTO_SHA1
 	select CRYPTO_HASH_INFO
+	select ASN1_ENCODER
+	select OID_REGISTRY
+	select ASN1
 	help
 	  This option provides support for creating, sealing, and unsealing
 	  keys in the kernel. Trusted keys are random number symmetric keys,
security/keys/trusted-keys/Makefile +3 -1
index 7b73cebbb378..f87c43f306d5 100644
@@ -5,4 +5,6 @@
 
 obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
 trusted-y += trusted_tpm1.o
-trusted-y += trusted_tpm2.o
+
+$(obj)/trusted_tpm2.o: $(obj)/tpm2key.asn1.h
+trusted-y += trusted_tpm2.o tpm2key.asn1.o
security/keys/trusted-keys/tpm2key.asn1 new file +11 -0
new file mode 100644
index 000000000000..3f6a9d01d1e5
@@ -0,0 +1,11 @@
+---
+--- ASN.1 for for TPM 2.0 keys
+---
+
+TPMKey ::= SEQUENCE {
+	type		OBJECT IDENTIFIER ({tpm2_key_type}),
+	emptyAuth	[0] EXPLICIT BOOLEAN OPTIONAL,
+	parent		INTEGER ({tpm2_key_parent}),
+	pubkey		OCTET STRING ({tpm2_key_pub}),
+	privkey		OCTET STRING ({tpm2_key_priv})
+	}
security/keys/trusted-keys/trusted_tpm1.c +1 -1
index eaa2e7ca136e..f235637865b9 100644
@@ -1011,7 +1011,7 @@ static int trusted_instantiate(struct key *key,
 		goto out;
 	}
 
-	if (!options->keyhandle) {
+	if (!options->keyhandle && !tpm2) {
 		ret = -EINVAL;
 		goto out;
 	}
security/keys/trusted-keys/trusted_tpm2.c +203 -7

274 lines not on this page · raw message

Signature · 1 line
2.26.2
#18 lore raw

Re: [PATCH v14 4/5] security: keys: trusted: use ASN.1 TPM2 key format for the blobs

Quoted 17 lines · James Bottomley
Quoted 16 lines · Jarkko Sakkinen
Quoted 14 lines · Jarkko Sakkinen
Quoted 9 lines · James Bottomley

On Mon, 2020-11-30 at 10:10 +0800, kernel test robot wrote:
[...]

Quoted 2 lines
Quoted 1 line

331 if (payload->blob_len < 0)

332 return payload->blob_len;

OK, I can rework this to use the signed version of blob len as below.

James

Do you have the patches in a git branch somewhere with this fixed?

I can take from there and apply.

Quoted 7 lines
Quoted 3 lines

CC my korg address. Sorry for the latency, I have this LKML migration going on (MAINTAINERS is already updated). Sometimes forgot to check this inbox.

I'm preparing a v15 but this is basically the only code change.

James

Please actually do. It's always nice to have a lore reference to the exact version that was merged.

/Jarkko

author maintainer
#19 lore raw

PATCH v14 5/5 security: keys: trusted: Make sealed key properly interoperable

In reply to James Bottomley

The current implementation appends a migratable flag to the end of a key, meaning the format isn't exactly interoperable because the using party needs to know to strip this extra byte. However, all other consumers of TPM sealed blobs expect the unseal to return exactly the key. Since TPM2 keys have a key property flag that corresponds to migratable, use that flag instead and make the actual key the only sealed quantity. This is secure because the key properties are bound to a hash in the private part, so if they're altered the key won't load.

Backwards compatibility is implemented by detecting whether we're loading a new format key or not and correctly setting migratable from the last byte of old format keys.

---

v2: added length checks to untrusted payload
v8: recover patch
v14: add tested by

---
 include/linux/tpm.h                       |  2 +
 security/keys/trusted-keys/trusted_tpm2.c | 53 ++++++++++++++++-------
 2 files changed, 40 insertions(+), 15 deletions(-)
include/linux/tpm.h +2 -0
index c4ca52138e8b..f1e32bc7d618 100644
@@ -305,6 +305,8 @@ struct tpm_buf {
 };
 
 enum tpm2_object_attributes {
+	TPM2_OA_FIXED_TPM		= BIT(1),
+	TPM2_OA_FIXED_PARENT		= BIT(4),
 	TPM2_OA_USER_WITH_AUTH		= BIT(6),
 };
 
security/keys/trusted-keys/trusted_tpm2.c +38 -15

105 lines not on this page · raw message

Signature · 1 line
2.26.2