public inbox for linux-integrity@vger.kernel.org
 help / color / mirror / Atom feed
From: James Bottomley <James.Bottomley@HansenPartnership.com>
To: Jarkko Sakkinen <jarkko@kernel.org>, linux-integrity@vger.kernel.org
Cc: keyrings@vger.kernel.org, Ard Biesheuvel <ardb@kernel.org>
Subject: Re: [PATCH v6 13/20] tpm: Add HMAC session start and end functions
Date: Wed, 03 Jan 2024 10:31:33 -0500	[thread overview]
Message-ID: <926f031e15739ea9044c8aaa7bbe72ab18a8f3c5.camel@HansenPartnership.com> (raw)
In-Reply-To: <CY566RG0WK3A.21KMYFHM9R6UR@suppilovahvero>

On Wed, 2024-01-03 at 17:18 +0200, Jarkko Sakkinen wrote:
> On Tue Jan 2, 2024 at 7:04 PM EET, James Bottomley wrote:
> > Add session  based HMAC  authentication plus parameter  decryption
> > and
> > response encryption  using AES. The  basic design is to  segregate
> > all
> > the nasty crypto, hash and hmac code into tpm2-sessions.c and
> > export a
> > usable API.  The API first of all starts off by gaining a session
> > with
> > tpm2_start_auth_session() which  initiates a session with  the TPM
> > and
> > allocates  an  opaque  tpm2_auth   structure  to  handle  the 
> > session
> > parameters.  The  design is that  session use will be  single
> > threaded
> > from start to finish under the ops lock, so the tpm2_auth structure
> > is
> > stored in struct tpm2_chip to simpify the externally visible API.
> > 
> > The session can be ended with tpm2_end_auth_session() which is
> > designed only to be used in error legs.  Ordinarily the further
> > session API (future patches) will end or continue the session
> > appropriately without having to call this.
> > 
> > Signed-off-by: James Bottomley
> > <James.Bottomley@HansenPartnership.com>
> > Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> # crypto
> > API parts
> > 
> > ---
> > 
> > v6: split into new patch, update config variable
> > ---
> >  drivers/char/tpm/Kconfig         |   3 +
> >  drivers/char/tpm/tpm-buf.c       |   1 +
> >  drivers/char/tpm/tpm-chip.c      |   3 +
> >  drivers/char/tpm/tpm2-sessions.c | 383
> > +++++++++++++++++++++++++++++++
> >  include/linux/tpm.h              |  34 +++
> >  5 files changed, 424 insertions(+)
> > 
> > diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
> > index e3c39a83171b..086cb8588493 100644
> > --- a/drivers/char/tpm/Kconfig
> > +++ b/drivers/char/tpm/Kconfig
> > @@ -30,6 +30,9 @@ if TCG_TPM
> >  config TCG_TPM2_HMAC
> >         bool "Use encrypted and HMACd transactions on the TPM bus"
> >         default y
> > +       select CRYPTO_ECDH
> > +       select CRYPTO_LIB_AESCFB
> > +       select CRYPTO_LIB_SHA256
> >         help
> >            Setting this causes us to deploy a scheme which uses
> > request
> >           and response HMACs in addition to encryption for
> > diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-
> > buf.c
> > index bb81180495d1..274130398569 100644
> > --- a/drivers/char/tpm/tpm-buf.c
> > +++ b/drivers/char/tpm/tpm-buf.c
> > @@ -44,6 +44,7 @@ void tpm_buf_reset(struct tpm_buf *buf, u16 tag,
> > u32 ordinal)
> >         head->tag = cpu_to_be16(tag);
> >         head->length = cpu_to_be32(sizeof(*head));
> >         head->ordinal = cpu_to_be32(ordinal);
> > +       buf->handles = 0;
> >  }
> >  EXPORT_SYMBOL_GPL(tpm_buf_reset);
> >  
> > diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-
> > chip.c
> > index 42b1062e33cd..d93937326b2e 100644
> > --- a/drivers/char/tpm/tpm-chip.c
> > +++ b/drivers/char/tpm/tpm-chip.c
> > @@ -275,6 +275,9 @@ static void tpm_dev_release(struct device *dev)
> >         kfree(chip->work_space.context_buf);
> >         kfree(chip->work_space.session_buf);
> >         kfree(chip->allocated_banks);
> > +#ifdef CONFIG_TCG_TPM2_HMAC
> > +       kfree(chip->auth);
> > +#endif
> >         kfree(chip);
> >  }
> >  
> > diff --git a/drivers/char/tpm/tpm2-sessions.c
> > b/drivers/char/tpm/tpm2-sessions.c
> > index ef66c28bb332..bca6fe3ebb10 100644
> > --- a/drivers/char/tpm/tpm2-sessions.c
> > +++ b/drivers/char/tpm/tpm2-sessions.c
> > @@ -3,18 +3,397 @@
> >  /*
> >   * Copyright (C) 2018 James.Bottomley@HansenPartnership.com
> >   *
> > + * Cryptographic helper routines for handling TPM2 sessions for
> > + * authorization HMAC and request response encryption.
> > + *
> > + * The idea is to ensure that every TPM command is HMAC protected
> > by a
> > + * session, meaning in-flight tampering would be detected and in
> > + * addition all sensitive inputs and responses should be
> > encrypted.
> > + *
> > + * The basic way this works is to use a TPM feature called salted
> > + * sessions where a random secret used in session construction is
> > + * encrypted to the public part of a known TPM key.  The problem
> > is we
> > + * have no known keys, so initially a primary Elliptic Curve key
> > is
> > + * derived from the NULL seed (we use EC because most TPMs
> > generate
> > + * these keys much faster than RSA ones).  The curve used is
> > NIST_P256
> > + * because that's now mandated to be present in 'TCG TPM v2.0
> > + * Provisioning Guidance'
> > + *
> > + * Threat problems: the initial TPM2_CreatePrimary is not (and
> > cannot
> > + * be) session protected, so a clever Man in the Middle could
> > return a
> > + * public key they control to this command and from there
> > intercept
> > + * and decode all subsequent session based transactions.  The
> > kernel
> > + * cannot mitigate this threat but, after boot, userspace can get
> > + * proof this has not happened by asking the TPM to certify the
> > NULL
> > + * key.  This certification would chain back to the TPM
> > Endorsement
> > + * Certificate and prove the NULL seed primary had not been
> > tampered
> > + * with and thus all sessions must have been cryptographically
> > secure.
> > + * To assist with this, the initial NULL seed public key name is
> > made
> > + * available in a sysfs file.
> > + *
> > + * Use of these functions:
> > + *
> > + * The design is all the crypto, hash and hmac gunk is confined in
> > this
> > + * file and never needs to be seen even by the kernel internal
> > user.  To
> > + * the user there's an init function tpm2_sessions_init() that
> > needs to
> > + * be called once per TPM which generates the NULL seed primary
> > key.
> > + *
> > + * These are the usage functions:
> > + *
> > + * tpm2_start_auth_session() which allocates the opaque auth
> > structure
> > + *     and gets a session from the TPM.  This must be called
> > before
> > + *     any of the following functions.  The session is protected
> > by a
> > + *     session_key which is derived from a random salt value
> > + *     encrypted to the NULL seed.
> > + * tpm2_end_auth_session() kills the session and frees the
> > resources.
> > + *     Under normal operation this function is done by
> > + *     tpm_buf_check_hmac_response(), so this is only to be used
> > on
> > + *     error legs where the latter is not executed.
> >   */
> >  
> >  #include "tpm.h"
> >  
> > +#include <linux/random.h>
> > +#include <linux/scatterlist.h>
> > +
> >  #include <asm/unaligned.h>
> >  
> >  #include <crypto/aes.h>
> > +#include <crypto/kpp.h>
> > +#include <crypto/ecdh.h>
> > +#include <crypto/hash.h>
> > +#include <crypto/hmac.h>
> >  
> >  /* if you change to AES256, you only need change this */
> >  #define AES_KEYBYTES   AES_KEYSIZE_128
> >  
> >  #define AES_KEYBITS    (AES_KEYBYTES*8)
> > +#define AUTH_MAX_NAMES 3
> > +
> > +/*
> > + * This is the structure that carries all the auth information
> > (like
> > + * session handle, nonces, session key and auth) from use to use
> > it is
> > + * designed to be opaque to anything outside.
> > + */
> > +struct tpm2_auth {
> > +       u32 handle;
> > +       /*
> > +        * This has two meanings: before
> > tpm_buf_fill_hmac_session()
> > +        * it marks the offset in the buffer of the start of the
> > +        * sessions (i.e. after all the handles).  Once the buffer
> > has
> > +        * been filled it markes the session number of our auth
> > +        * session so we can find it again in the response buffer.
> > +        *
> > +        * The two cases are distinguished because the first offset
> > +        * must always be greater than TPM_HEADER_SIZE and the
> > second
> > +        * must be less than or equal to 5.
> > +        */
> > +       u32 session;
> > +       /*
> > +        * the size here is variable and set by the size of
> > our_nonce
> > +        * which must be between 16 and the name hash length. we
> > set
> > +        * the maximum sha256 size for the greatest protection
> > +        */
> > +       u8 our_nonce[SHA256_DIGEST_SIZE];
> > +       u8 tpm_nonce[SHA256_DIGEST_SIZE];
> > +       /*
> > +        * the salt is only used across the session
> > command/response
> > +        * after that it can be used as a scratch area
> > +        */
> > +       union {
> > +               u8 salt[EC_PT_SZ];
> > +               /* scratch for key + IV */
> > +               u8 scratch[AES_KEYBYTES + AES_BLOCK_SIZE];
> > +       };
> > +       u8 session_key[SHA256_DIGEST_SIZE];
> > +};
> 
> Could this contain also the fields added in the previous patch?
> 
> Then obviously this data would be allocated together with chip
> but is there hard reason why this needs separate kzalloc and cannot
> be always allocated with chip blob?

It's session specific (and highly sensitive data), so it needs to be
allocated and destroyed with each session.  Our usage pattern under the
ops mutex means that every session is single threaded, so effectively
it has a 1:1 relationship with the chip, but part of the reason for all
of this is to remove visibility of the contents of this area from
anything other than the session code.  Essentially it's stuff the chip
doesn't need to know because it's always constructed when the session
is created.

I've also got a policy patch much later that requires two sessions, so
needs a push and pop mechanism which a static allocation in the chip
area won't work for.

James


  reply	other threads:[~2024-01-03 15:31 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-02 17:03 [PATCH v6 00/20] add integrity and security to TPM2 transactions James Bottomley
2024-01-02 17:03 ` [PATCH v6 01/20] tpm: Remove unused tpm_buf_tag() James Bottomley
2024-01-02 17:03 ` [PATCH v6 02/20] tpm: Remove tpm_send() James Bottomley
2024-01-02 17:03 ` [PATCH v6 03/20] tpm: Move buffer handling from static inlines to real functions James Bottomley
2024-01-02 17:03 ` [PATCH v6 04/20] tpm: Update struct tpm_buf documentation comments James Bottomley
2024-01-02 17:03 ` [PATCH v6 05/20] tpm: Store the length of the tpm_buf data separately James Bottomley
2024-01-02 17:03 ` [PATCH v6 06/20] tpm: TPM2B formatted buffers James Bottomley
2024-01-02 17:03 ` [PATCH v6 07/20] tpm: Add tpm_buf_read_{u8,u16,u32} James Bottomley
2024-01-02 17:03 ` [PATCH v6 08/20] KEYS: trusted: tpm2: Use struct tpm_buf for sized buffers James Bottomley
2024-01-02 17:03 ` [PATCH v6 09/20] crypto: lib - implement library version of AES in CFB mode James Bottomley
2024-01-03 14:59   ` Jarkko Sakkinen
2024-01-02 17:03 ` [PATCH v6 10/20] tpm: add buffer function to point to returned parameters James Bottomley
2024-01-03 15:00   ` Jarkko Sakkinen
2024-01-02 17:03 ` [PATCH v6 11/20] tpm: export the context save and load commands James Bottomley
2024-01-03 15:01   ` Jarkko Sakkinen
2024-01-02 17:04 ` [PATCH v6 12/20] tpm: Add NULL primary creation James Bottomley
2024-01-03 15:11   ` Jarkko Sakkinen
2024-01-03 15:25     ` James Bottomley
2024-01-04 17:56       ` Jarkko Sakkinen
2024-01-02 17:04 ` [PATCH v6 13/20] tpm: Add HMAC session start and end functions James Bottomley
2024-01-03 15:18   ` Jarkko Sakkinen
2024-01-03 15:31     ` James Bottomley [this message]
2024-01-04 18:09       ` Jarkko Sakkinen
2024-01-04 22:25         ` James Bottomley
2024-01-05 15:36           ` Jarkko Sakkinen
2024-01-02 17:04 ` [PATCH v6 14/20] tpm: Add HMAC session name/handle append James Bottomley
2024-01-03 15:19   ` Jarkko Sakkinen
2024-01-02 17:04 ` [PATCH v6 15/20] tpm: Add the rest of the session HMAC API James Bottomley
2024-01-03 15:20   ` Jarkko Sakkinen
2024-01-02 17:04 ` [PATCH v6 16/20] tpm: add hmac checks to tpm2_pcr_extend() James Bottomley
2024-01-03 15:21   ` Jarkko Sakkinen
2024-01-02 17:04 ` [PATCH v6 17/20] tpm: add session encryption protection to tpm2_get_random() James Bottomley
2024-01-03 15:21   ` Jarkko Sakkinen
2024-01-02 17:04 ` [PATCH v6 18/20] KEYS: trusted: Add session encryption protection to the seal/unseal path James Bottomley
2024-01-03 15:22   ` Jarkko Sakkinen
2024-01-02 17:04 ` [PATCH v6 19/20] tpm: add the null key name as a sysfs export James Bottomley
2024-01-03 15:22   ` Jarkko Sakkinen
2024-01-02 17:04 ` [PATCH v6 20/20] Documentation: add tpm-security.rst James Bottomley
2024-01-03 15:24   ` Jarkko Sakkinen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=926f031e15739ea9044c8aaa7bbe72ab18a8f3c5.camel@HansenPartnership.com \
    --to=james.bottomley@hansenpartnership.com \
    --cc=ardb@kernel.org \
    --cc=jarkko@kernel.org \
    --cc=keyrings@vger.kernel.org \
    --cc=linux-integrity@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox