diff mbox series

[v12,4/5] security: keys: trusted: use ASN.1 TPM2 key format for the blobs

Message ID 20200920163351.11293-5-James.Bottomley@HansenPartnership.com (mailing list archive)
State New
Headers show
Series TPM 2.0 trusted key rework | expand

Commit Message

James Bottomley Sept. 20, 2020, 4:33 p.m. UTC
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.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

---
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
---
 .../security/keys/trusted-encrypted.rst       |  58 +++++
 include/keys/trusted-type.h                   |   1 +
 security/keys/Kconfig                         |   1 +
 security/keys/trusted-keys/Makefile           |   2 +-
 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, 274 insertions(+), 8 deletions(-)
 create mode 100644 security/keys/trusted-keys/tpm2key.asn1

Comments

kernel test robot Sept. 21, 2020, 12:07 a.m. UTC | #1
Hi James,

I love your patch! Yet something to improve:

[auto build test ERROR on integrity/next-integrity]
[also build test ERROR on linus/master v5.9-rc5 next-20200918]
[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/20200921-003922
base:   https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git next-integrity
config: x86_64-randconfig-a003-20200921 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project f4e554180962aa6bc93678898b6933ea712bde50)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install x86_64 cross compiling tool for clang build
        # apt-get install binutils-x86-64-linux-gnu
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> make[4]: *** No rule to make target 'security/keys/trusted-keys/tpm2key.asn1.o', needed by 'security/keys/trusted-keys/built-in.a'.
   make[4]: *** [scripts/Makefile.build:283: security/keys/trusted-keys/trusted_tpm2.o] Error 1
   make[4]: Target '__build' not remade because of errors.

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
James Bottomley Sept. 21, 2020, 9:31 p.m. UTC | #2
On Mon, 2020-09-21 at 08:07 +0800, kernel test robot wrote:
> Hi James,
> 
> I love your patch! Yet something to improve:
> 
> [auto build test ERROR on integrity/next-integrity]
> [also build test ERROR on linus/master v5.9-rc5 next-20200918]
> [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/20200921-003922
> base:   
> https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
> next-integrity
> config: x86_64-randconfig-a003-20200921 (attached as .config)
> compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project
> f4e554180962aa6bc93678898b6933ea712bde50)
> reproduce (this is a W=1 build):
>         wget 
> https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross
> -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # install x86_64 cross compiling tool for clang build
>         # apt-get install binutils-x86-64-linux-gnu
>         # save the attached .config to linux build tree
>         COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross
> ARCH=x86_64 
> 
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>
> 
> All errors (new ones prefixed by >>):
> 
> > > make[4]: *** No rule to make target 'security/keys/trusted-
> > > keys/tpm2key.asn1.o', needed by 'security/keys/trusted-
> > > keys/built-in.a'.
>    make[4]: *** [scripts/Makefile.build:283: security/keys/trusted-
> keys/trusted_tpm2.o] Error 1
>    make[4]: Target '__build' not remade because of errors.


So can I still add that tracking this down involved installing an
entirely unnecessary ARM build environment, which was a huge effort I
didn't need to do if you'd just provided the build log which fingered
the ASN.1 compiler problem if you know what to look for.

The reason for the problem is because ASN1 isn't selected in the
Kconfig which causes the ASN.1 compiler not to be built.  The way our
current build rules are structured causes the make rule for this simply
to be skipped, which means you have to know to look for the absence of
ASN.1 in the build log.  I propose adding this to the build rules,
which produces the much more explicit:

/home/jejb/git/linux-build/scripts/Makefile.build:387: *** CONFIG_ASN1 must be defined for the asn1_compiler.  Stop.
make[3]: *** [/home/jejb/git/linux-build/scripts/Makefile.build:505: security/keys/trusted-keys] Error 2

James

---

diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index a467b9323442..bca7003beac8 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -382,6 +382,11 @@ quiet_cmd_asn1_compiler = ASN.1   $(basename $@).[ch]
       cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \
 				$(basename $@).c $(basename $@).h
 
+ifndef CONFIG_ASN1
+$(objtree)/scripts/asn1_compiler:
+	$(error CONFIG_ASN1 must be defined for the asn1_compiler)
+endif
+
 $(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler
 	$(call cmd,asn1_compiler)
Nick Desaulniers Sept. 22, 2020, 7:14 p.m. UTC | #3
On Mon, Sep 21, 2020 at 2:31 PM James Bottomley
<James.Bottomley@hansenpartnership.com> wrote:
>
> On Mon, 2020-09-21 at 08:07 +0800, kernel test robot wrote:
> > Hi James,
> >
> > I love your patch! Yet something to improve:
> >
> > [auto build test ERROR on integrity/next-integrity]
> > [also build test ERROR on linus/master v5.9-rc5 next-20200918]
> > [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/20200921-003922
> > base:
> > https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
> > next-integrity
> > config: x86_64-randconfig-a003-20200921 (attached as .config)
> > compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project
> > f4e554180962aa6bc93678898b6933ea712bde50)
> > reproduce (this is a W=1 build):
> >         wget
> > https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross
> > -O ~/bin/make.cross
> >         chmod +x ~/bin/make.cross
> >         # install x86_64 cross compiling tool for clang build
> >         # apt-get install binutils-x86-64-linux-gnu
> >         # save the attached .config to linux build tree
> >         COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross
> > ARCH=x86_64
> >
> > If you fix the issue, kindly add following tag as appropriate
> > Reported-by: kernel test robot <lkp@intel.com>
> >
> > All errors (new ones prefixed by >>):
> >
> > > > make[4]: *** No rule to make target 'security/keys/trusted-
> > > > keys/tpm2key.asn1.o', needed by 'security/keys/trusted-
> > > > keys/built-in.a'.
> >    make[4]: *** [scripts/Makefile.build:283: security/keys/trusted-
> > keys/trusted_tpm2.o] Error 1
> >    make[4]: Target '__build' not remade because of errors.
>
>
> So can I still add that tracking this down involved installing an
> entirely unnecessary ARM build environment, which was a huge effort I
> didn't need to do if you'd just provided the build log which fingered
> the ASN.1 compiler problem if you know what to look for.

Having a link to the build log artifact is a valid criticism.

>
> The reason for the problem is because ASN1 isn't selected in the
> Kconfig which causes the ASN.1 compiler not to be built.  The way our
> current build rules are structured causes the make rule for this simply
> to be skipped, which means you have to know to look for the absence of
> ASN.1 in the build log.  I propose adding this to the build rules,
> which produces the much more explicit:
>
> /home/jejb/git/linux-build/scripts/Makefile.build:387: *** CONFIG_ASN1 must be defined for the asn1_compiler.  Stop.
> make[3]: *** [/home/jejb/git/linux-build/scripts/Makefile.build:505: security/keys/trusted-keys] Error 2
>
> James
>
> ---
>
> diff --git a/scripts/Makefile.build b/scripts/Makefile.build
> index a467b9323442..bca7003beac8 100644
> --- a/scripts/Makefile.build
> +++ b/scripts/Makefile.build
> @@ -382,6 +382,11 @@ quiet_cmd_asn1_compiler = ASN.1   $(basename $@).[ch]
>        cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \
>                                 $(basename $@).c $(basename $@).h
>
> +ifndef CONFIG_ASN1
> +$(objtree)/scripts/asn1_compiler:
> +       $(error CONFIG_ASN1 must be defined for the asn1_compiler)
> +endif
> +
>  $(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler
>         $(call cmd,asn1_compiler)

Is there a better way via Kconfig to gate whatever consumes
CONFIG_ASN1 on CONFIG_ASN1 being set, rather than erroring for
randconfig builds? I don't see how the diff would solve the case of CI
systems doing randconfig builds.
James Bottomley Sept. 22, 2020, 7:31 p.m. UTC | #4
On Tue, 2020-09-22 at 12:14 -0700, Nick Desaulniers wrote:
> On Mon, Sep 21, 2020 at 2:31 PM James Bottomley
> <James.Bottomley@hansenpartnership.com> wrote:
> > On Mon, 2020-09-21 at 08:07 +0800, kernel test robot wrote:
> > > Hi James,
> > > 
> > > I love your patch! Yet something to improve:
> > > 
> > > [auto build test ERROR on integrity/next-integrity]
> > > [also build test ERROR on linus/master v5.9-rc5 next-20200918]
> > > [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/20200921-003922
> > > base:
> > > https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
> > > next-integrity
> > > config: x86_64-randconfig-a003-20200921 (attached as .config)
> > > compiler: clang version 12.0.0 (
> > > https://github.com/llvm/llvm-project
> > > f4e554180962aa6bc93678898b6933ea712bde50)
> > > reproduce (this is a W=1 build):
> > >         wget
> > > https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross
> > > -O ~/bin/make.cross
> > >         chmod +x ~/bin/make.cross
> > >         # install x86_64 cross compiling tool for clang build
> > >         # apt-get install binutils-x86-64-linux-gnu
> > >         # save the attached .config to linux build tree
> > >         COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang
> > > make.cross
> > > ARCH=x86_64
> > > 
> > > If you fix the issue, kindly add following tag as appropriate
> > > Reported-by: kernel test robot <lkp@intel.com>
> > > 
> > > All errors (new ones prefixed by >>):
> > > 
> > > > > make[4]: *** No rule to make target 'security/keys/trusted-
> > > > > keys/tpm2key.asn1.o', needed by 'security/keys/trusted-
> > > > > keys/built-in.a'.
> > >    make[4]: *** [scripts/Makefile.build:283:
> > > security/keys/trusted-
> > > keys/trusted_tpm2.o] Error 1
> > >    make[4]: Target '__build' not remade because of errors.
> > 
> > So can I still add that tracking this down involved installing an
> > entirely unnecessary ARM build environment, which was a huge effort
> > I didn't need to do if you'd just provided the build log which
> > fingered the ASN.1 compiler problem if you know what to look for.
> 
> Having a link to the build log artifact is a valid criticism.

Heh, I'm just annoyed because when I finally got the ARM environment
installed and the problem replicated, I realised it could be reproduced
with an x86 build ... just one that would never be useful in practice.

> > The reason for the problem is because ASN1 isn't selected in the
> > Kconfig which causes the ASN.1 compiler not to be built.  The way
> > our current build rules are structured causes the make rule for
> > this simply to be skipped, which means you have to know to look for
> > the absence of ASN.1 in the build log.  I propose adding this to
> > the build rules, which produces the much more explicit:
> > 
> > /home/jejb/git/linux-build/scripts/Makefile.build:387: ***
> > CONFIG_ASN1 must be defined for the asn1_compiler.  Stop.
> > make[3]: *** [/home/jejb/git/linux-
> > build/scripts/Makefile.build:505: security/keys/trusted-keys] Error
> > 2
> > 
> > James
> > 
> > ---
> > 
> > diff --git a/scripts/Makefile.build b/scripts/Makefile.build
> > index a467b9323442..bca7003beac8 100644
> > --- a/scripts/Makefile.build
> > +++ b/scripts/Makefile.build
> > @@ -382,6 +382,11 @@ quiet_cmd_asn1_compiler = ASN.1   $(basename
> > $@).[ch]
> >        cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \
> >                                 $(basename $@).c $(basename $@).h
> > 
> > +ifndef CONFIG_ASN1
> > +$(objtree)/scripts/asn1_compiler:
> > +       $(error CONFIG_ASN1 must be defined for the asn1_compiler)
> > +endif
> > +
> >  $(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1
> > $(objtree)/scripts/asn1_compiler
> >         $(call cmd,asn1_compiler)
> 
> Is there a better way via Kconfig to gate whatever consumes
> CONFIG_ASN1 on CONFIG_ASN1 being set, rather than erroring for
> randconfig builds? I don't see how the diff would solve the case of
> CI systems doing randconfig builds.

Well, no there's an actual bug: all consumers of asn1_compile need a
select ASN1.  This was missing from the v12 patch and is now included
in the v13 one.  This Makefile.build patch here was just to make the
problem explicit in the 0day logs if it ever occurs again.

The reason it only showed up on arm32 is that pretty much only an
embedded kernel is cut down enough to create a randconfig that doesn't
pull in CRYPTO_RSA, which also selects ASN1 and hides the problem.

James
diff mbox series

Patch

diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst
index 9483a7425ad5..eb639bb24fcc 100644
--- a/Documentation/security/keys/trusted-encrypted.rst
+++ b/Documentation/security/keys/trusted-encrypted.rst
@@ -208,3 +208,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.
diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
index b2ed3481c6a0..b2d87ad21714 100644
--- a/include/keys/trusted-type.h
+++ b/include/keys/trusted-type.h
@@ -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];
 };
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index 83bc23409164..8fbfedf6d1cc 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -75,6 +75,7 @@  config TRUSTED_KEYS
 	select CRYPTO_HMAC
 	select CRYPTO_SHA1
 	select CRYPTO_HASH_INFO
+	select ASN1_ENCODER
 	help
 	  This option provides support for creating, sealing, and unsealing
 	  keys in the kernel. Trusted keys are random number symmetric keys,
diff --git a/security/keys/trusted-keys/Makefile b/security/keys/trusted-keys/Makefile
index 7b73cebbb378..e0198641eff2 100644
--- a/security/keys/trusted-keys/Makefile
+++ b/security/keys/trusted-keys/Makefile
@@ -5,4 +5,4 @@ 
 
 obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
 trusted-y += trusted_tpm1.o
-trusted-y += trusted_tpm2.o
+trusted-y += trusted_tpm2.o tpm2key.asn1.o
diff --git a/security/keys/trusted-keys/tpm2key.asn1 b/security/keys/trusted-keys/tpm2key.asn1
new file mode 100644
index 000000000000..3f6a9d01d1e5
--- /dev/null
+++ b/security/keys/trusted-keys/tpm2key.asn1
@@ -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})
+	}
diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
index eaa2e7ca136e..f235637865b9 100644
--- a/security/keys/trusted-keys/trusted_tpm1.c
+++ b/security/keys/trusted-keys/trusted_tpm1.c
@@ -1011,7 +1011,7 @@  static int trusted_instantiate(struct key *key,
 		goto out;
 	}
 
-	if (!options->keyhandle) {
+	if (!options->keyhandle && !tpm2) {
 		ret = -EINVAL;
 		goto out;
 	}
diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index b4a5058107c2..e8dcc47b3388 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -4,6 +4,8 @@ 
  * Copyright (C) 2014 Intel Corporation
  */
 
+#include <linux/asn1_encoder.h>
+#include <linux/oid_registry.h>
 #include <linux/string.h>
 #include <linux/err.h>
 #include <linux/tpm.h>
@@ -12,6 +14,10 @@ 
 #include <keys/trusted-type.h>
 #include <keys/trusted_tpm.h>
 
+#include <asm/unaligned.h>
+
+#include "tpm2key.asn1.h"
+
 static struct tpm2_hash tpm2_hash_map[] = {
 	{HASH_ALGO_SHA1, TPM_ALG_SHA1},
 	{HASH_ALGO_SHA256, TPM_ALG_SHA256},
@@ -20,6 +26,165 @@  static struct tpm2_hash tpm2_hash_map[] = {
 	{HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
 };
 
+static u32 tpm2key_oid[] = { 2,23,133,10,1,5 };
+
+static int tpm2_key_encode(struct trusted_key_payload *payload,
+			   struct trusted_key_options *options,
+			   u8 *src, u32 len)
+{
+	const int SCRATCH_SIZE = PAGE_SIZE;
+	u8 *scratch = kmalloc(SCRATCH_SIZE, GFP_KERNEL);
+	u8 *work = scratch, *work1;
+	u8 *end_work = scratch + SCRATCH_SIZE;
+	u8 *priv, *pub;
+	u16 priv_len, pub_len;
+
+	priv_len = get_unaligned_be16(src) + 2;
+	priv = src;
+
+	src += priv_len;
+
+	pub_len = get_unaligned_be16(src) + 2;
+	pub = src;
+
+	if (!scratch)
+		return -ENOMEM;
+
+	work = asn1_encode_oid(work, end_work, tpm2key_oid,
+			       asn1_oid_len(tpm2key_oid));
+
+	if (options->blobauth_len == 0) {
+		unsigned char bool[3], *w = bool;
+		/* tag 0 is emptyAuth */
+		w = asn1_encode_boolean(w, w + sizeof(bool), true);
+		if (WARN(IS_ERR(w), "BUG: Boolean failed to encode"))
+			return PTR_ERR(w);
+		work = asn1_encode_tag(work, end_work, 0, bool, w - bool);
+	}
+
+	/*
+	 * Assume both octet strings will encode to a 2 byte definite length
+	 *
+	 * Note: For a well behaved TPM, this warning should never
+	 * trigger, so if it does there's something nefarious going on
+	 */
+	if (WARN(work - scratch + pub_len + priv_len + 14 > SCRATCH_SIZE,
+		 "BUG: scratch buffer is too small"))
+		return -EINVAL;
+
+	work = asn1_encode_integer(work, end_work, options->keyhandle);
+	work = asn1_encode_octet_string(work, end_work, pub, pub_len);
+	work = asn1_encode_octet_string(work, end_work, priv, priv_len);
+
+	work1 = payload->blob;
+	work1 = asn1_encode_sequence(work1, work1 + sizeof(payload->blob),
+				     scratch, work - scratch);
+	if (WARN(IS_ERR(work1), "BUG: ASN.1 encoder failed"))
+		return PTR_ERR(work1);
+
+	return work1 - payload->blob;
+}
+
+struct tpm2_key_context {
+	u32 parent;
+	const u8 *pub;
+	u32 pub_len;
+	const u8 *priv;
+	u32 priv_len;
+};
+
+static int tpm2_key_decode(struct trusted_key_payload *payload,
+			   struct trusted_key_options *options,
+			   u8 **buf)
+{
+	int ret;
+	struct tpm2_key_context ctx;
+	u8 *blob;
+
+	memset(&ctx, 0, sizeof(ctx));
+
+	ret = asn1_ber_decoder(&tpm2key_decoder, &ctx, payload->blob,
+			       payload->blob_len);
+	if (ret < 0)
+		return ret;
+
+	if (ctx.priv_len + ctx.pub_len > MAX_BLOB_SIZE)
+		return -EINVAL;
+
+	blob = kmalloc(ctx.priv_len + ctx.pub_len + 4, GFP_KERNEL);
+	if (!blob)
+		return -ENOMEM;
+
+	*buf = blob;
+	options->keyhandle = ctx.parent;
+
+	memcpy(blob, ctx.priv, ctx.priv_len);
+	blob += ctx.priv_len;
+
+	memcpy(blob, ctx.pub, ctx.pub_len);
+
+	return 0;
+}
+
+int tpm2_key_parent(void *context, size_t hdrlen,
+		  unsigned char tag,
+		  const void *value, size_t vlen)
+{
+	struct tpm2_key_context *ctx = context;
+	const u8 *v = value;
+	int i;
+
+	ctx->parent = 0;
+	for (i = 0; i < vlen; i++) {
+		ctx->parent <<= 8;
+		ctx->parent |= v[i];
+	}
+
+	return 0;
+}
+
+int tpm2_key_type(void *context, size_t hdrlen,
+		unsigned char tag,
+		const void *value, size_t vlen)
+{
+	enum OID oid = look_up_OID(value, vlen);
+
+	if (oid != OID_TPMSealedData) {
+		char buffer[50];
+
+		sprint_oid(value, vlen, buffer, sizeof(buffer));
+		pr_debug("OID is \"%s\" which is not TPMSealedData\n",
+			 buffer);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int tpm2_key_pub(void *context, size_t hdrlen,
+	       unsigned char tag,
+	       const void *value, size_t vlen)
+{
+	struct tpm2_key_context *ctx = context;
+
+	ctx->pub = value;
+	ctx->pub_len = vlen;
+
+	return 0;
+}
+
+int tpm2_key_priv(void *context, size_t hdrlen,
+		unsigned char tag,
+		const void *value, size_t vlen)
+{
+	struct tpm2_key_context *ctx = context;
+
+	ctx->priv = value;
+	ctx->priv_len = vlen;
+
+	return 0;
+}
+
 /**
  * tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer.
  *
@@ -79,6 +244,9 @@  int tpm2_seal_trusted(struct tpm_chip *chip,
 	if (i == ARRAY_SIZE(tpm2_hash_map))
 		return -EINVAL;
 
+	if (!options->keyhandle)
+		return -EINVAL;
+
 	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
 	if (rc)
 		return rc;
@@ -146,8 +314,10 @@  int tpm2_seal_trusted(struct tpm_chip *chip,
 		goto out;
 	}
 
-	memcpy(payload->blob, &buf.data[TPM_HEADER_SIZE + 4], blob_len);
-	payload->blob_len = blob_len;
+	payload->blob_len =
+		tpm2_key_encode(payload, options,
+				&buf.data[TPM_HEADER_SIZE + 4],
+				blob_len);
 
 out:
 	tpm_buf_destroy(&buf);
@@ -158,6 +328,8 @@  int tpm2_seal_trusted(struct tpm_chip *chip,
 		else
 			rc = -EPERM;
 	}
+	if (payload->blob_len < 0)
+		return payload->blob_len;
 
 	return rc;
 }
@@ -184,13 +356,34 @@  static int tpm2_load_cmd(struct tpm_chip *chip,
 	unsigned int private_len;
 	unsigned int public_len;
 	unsigned int blob_len;
+	u8 *blob;
 	int rc;
 
-	private_len = be16_to_cpup((__be16 *) &payload->blob[0]);
-	if (private_len > (payload->blob_len - 2))
+	rc = tpm2_key_decode(payload, options, &blob);
+	if (rc) {
+		/* old form */
+		blob = payload->blob;
+		payload->old_format = 1;
+	}
+
+	/* new format carries keyhandle but old format doesn't */
+	if (!options->keyhandle)
+		return -EINVAL;
+
+	/* must be big enough for at least the two be16 size counts */
+	if (payload->blob_len < 4)
+		return -EINVAL;
+
+	private_len = get_unaligned_be16(blob);
+
+	/* must be big enough for following public_len */
+	if (private_len + 2 + 2 > (payload->blob_len))
+		return -E2BIG;
+
+	public_len = get_unaligned_be16(blob + 2 + private_len);
+	if (private_len + 2 + public_len + 2 > payload->blob_len)
 		return -E2BIG;
 
-	public_len = be16_to_cpup((__be16 *) &payload->blob[2 + private_len]);
 	blob_len = private_len + public_len + 4;
 	if (blob_len > payload->blob_len)
 		return -E2BIG;
@@ -206,7 +399,7 @@  static int tpm2_load_cmd(struct tpm_chip *chip,
 			     options->keyauth /* hmac */,
 			     TPM_DIGEST_SIZE);
 
-	tpm_buf_append(&buf, payload->blob, blob_len);
+	tpm_buf_append(&buf, blob, blob_len);
 
 	if (buf.flags & TPM_BUF_OVERFLOW) {
 		rc = -E2BIG;
@@ -219,6 +412,8 @@  static int tpm2_load_cmd(struct tpm_chip *chip,
 			(__be32 *) &buf.data[TPM_HEADER_SIZE]);
 
 out:
+	if (blob != payload->blob)
+		kfree(blob);
 	tpm_buf_destroy(&buf);
 
 	if (rc > 0)