On Mon Apr 29, 2024 at 11:28 PM EEST, James Bottomley wrote: > The TCG mandates two Key derivation functions called KDFa and KDFe > used to derive keys from seeds and elliptic curve points respectively. > The definitions for these functions are found in the TPM 2.0 Library > Specification Part 1 - Architecture Guide > > https://trustedcomputinggroup.org/resource/tpm-library-specification/ > > Implement a cut down version of each of these functions sufficient to > support the key derivation needs of HMAC sessions. > > Signed-off-by: James Bottomley <James.Bottomley@xxxxxxxxxxxxxxxxxxxxx> > > --- > > v8: Add new patch containing KDFs > --- > drivers/char/tpm/Kconfig | 1 + > drivers/char/tpm/tpm2-sessions.c | 105 +++++++++++++++++++++++++++++++ > 2 files changed, 106 insertions(+) > > diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig > index ab16d347579f..4873e6eae255 100644 > --- a/drivers/char/tpm/Kconfig > +++ b/drivers/char/tpm/Kconfig > @@ -30,6 +30,7 @@ if TCG_TPM > config TCG_TPM2_HMAC > bool "Use HMAC and encrypted transactions on the TPM bus" > default y > + 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/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c > index fc3f032df467..8429e596f1eb 100644 > --- a/drivers/char/tpm/tpm2-sessions.c > +++ b/drivers/char/tpm/tpm2-sessions.c > @@ -7,6 +7,111 @@ > > #include "tpm.h" > #include <asm/unaligned.h> > +#include <crypto/hash.h> > +#include <crypto/hmac.h> > + > +/* > + * It turns out the crypto hmac(sha256) is hard for us to consume > + * because it assumes a fixed key and the TPM seems to change the key > + * on every operation, so we weld the hmac init and final functions in > + * here to give it the same usage characteristics as a regular hash > + */ > +static void tpm2_hmac_init(struct sha256_state *sctx, u8 *key, u32 key_len) > +{ > + u8 pad[SHA256_BLOCK_SIZE]; > + int i; > + > + sha256_init(sctx); > + for (i = 0; i < sizeof(pad); i++) { > + if (i < key_len) > + pad[i] = key[i]; > + else > + pad[i] = 0; > + pad[i] ^= HMAC_IPAD_VALUE; > + } > + sha256_update(sctx, pad, sizeof(pad)); > +} > + > +static void tpm2_hmac_final(struct sha256_state *sctx, u8 *key, u32 key_len, > + u8 *out) > +{ > + u8 pad[SHA256_BLOCK_SIZE]; > + int i; > + > + for (i = 0; i < sizeof(pad); i++) { > + if (i < key_len) > + pad[i] = key[i]; > + else > + pad[i] = 0; > + pad[i] ^= HMAC_OPAD_VALUE; > + } > + > + /* collect the final hash; use out as temporary storage */ > + sha256_final(sctx, out); > + > + sha256_init(sctx); > + sha256_update(sctx, pad, sizeof(pad)); > + sha256_update(sctx, out, SHA256_DIGEST_SIZE); > + sha256_final(sctx, out); > +} > + > +/* > + * assume hash sha256 and nonces u, v of size SHA256_DIGEST_SIZE but > + * otherwise standard tpm2_KDFa. Note output is in bytes not bits. > + */ > +static void tpm2_KDFa(u8 *key, u32 key_len, const char *label, u8 *u, > + u8 *v, u32 bytes, u8 *out) > +{ > + u32 counter = 1; > + const __be32 bits = cpu_to_be32(bytes * 8); > + > + while (bytes > 0) { > + struct sha256_state sctx; > + __be32 c = cpu_to_be32(counter); > + > + tpm2_hmac_init(&sctx, key, key_len); > + sha256_update(&sctx, (u8 *)&c, sizeof(c)); > + sha256_update(&sctx, label, strlen(label)+1); > + sha256_update(&sctx, u, SHA256_DIGEST_SIZE); > + sha256_update(&sctx, v, SHA256_DIGEST_SIZE); > + sha256_update(&sctx, (u8 *)&bits, sizeof(bits)); > + tpm2_hmac_final(&sctx, key, key_len, out); > + > + bytes -= SHA256_DIGEST_SIZE; > + counter++; > + out += SHA256_DIGEST_SIZE; > + } > +} > + > +/* > + * Somewhat of a bastardization of the real KDFe. We're assuming > + * we're working with known point sizes for the input parameters and > + * the hash algorithm is fixed at sha256. Because we know that the > + * point size is 32 bytes like the hash size, there's no need to loop > + * in this KDF. > + */ > +static void tpm2_KDFe(u8 z[EC_PT_SZ], const char *str, u8 *pt_u, u8 *pt_v, > + u8 *out) > +{ > + struct sha256_state sctx; > + /* > + * this should be an iterative counter, but because we know > + * we're only taking 32 bytes for the point using a sha256 > + * hash which is also 32 bytes, there's only one loop > + */ > + __be32 c = cpu_to_be32(1); > + > + sha256_init(&sctx); > + /* counter (BE) */ > + sha256_update(&sctx, (u8 *)&c, sizeof(c)); > + /* secret value */ > + sha256_update(&sctx, z, EC_PT_SZ); > + /* string including trailing zero */ > + sha256_update(&sctx, str, strlen(str)+1); > + sha256_update(&sctx, pt_u, EC_PT_SZ); > + sha256_update(&sctx, pt_v, EC_PT_SZ); > + sha256_final(&sctx, out); > +} > > /** > * tpm2_parse_create_primary() - parse the data returned from TPM_CC_CREATE_PRIMARY Reviewed-by: Jarkko Sakkinen <jarkko@xxxxxxxxxx> BR, Jarkko