2024-05-22 00:54:13

by Jarkko Sakkinen

[permalink] [raw]
Subject: [PATCH v4 0/5] KEYS: asymmetric: tpm2_key_rsa

## Overview

Introduce tpm2_key_rsa module, which implements asymmetric TPM2 RSA key.
The feature can be enabled with the CONFIG_ASYMMETRIC_TPM2_KEY_RSA_SUBTYPE
kconfig option. This feature allows the private key to be uploaded to
the TPM2 for signing, and software can use the public key to verify
the signatures.

The idea in the design is to over time to have submodule per key type
For instance, tpm2_key_ecdsa could be one potential future addition in
the future. Perhaps, it might sense to consider at that point also a
top-level tpm2_key module. The gist is that the naming convention is
free from potential future bottlencks.

### Testing

tpm2_createprimary --hierarchy o -G rsa2048 -c owner.txt
tpm2_evictcontrol -c owner.txt 0x81000001
tpm2_getcap handles-persistent
openssl genrsa -out private.pem 2048
tpm2_import -C 0x81000001 -G rsa -i private.pem -u key.pub -r key.priv
tpm2_encodeobject -C 0x81000001 -u key.pub -r key.priv -o key.priv.pem
openssl asn1parse -inform pem -in key.priv.pem -noout -out key.priv.der
serial=`cat key.priv.der | keyctl padd asymmetric tpm @u`
echo "abcdefg" > plaintext.txt
keyctl pkey_encrypt $serial 0 plaintext.txt enc=pkcs1 > encrypted.dat
keyctl pkey_decrypt $serial 0 encrypted.dat enc=pkcs1 > decrypted.dat
keyctl pkey_sign $serial 0 plaintext.txt enc=pkcs1 hash=sha256 > signed.dat
keyctl pkey_verify $serial 0 plaintext.txt signed.dat enc=pkcs1 hash=sha256

## References

- v1: https://lore.kernel.org/linux-integrity/[email protected]/
- Derived from https://lore.kernel.org/all/[email protected]/

James Prestwood (1):
keys: asymmetric: ASYMMETRIC_TPM2_KEY_RSA_SUBTYPE

Jarkko Sakkinen (4):
crypto: rsa-pkcs1pad: export rsa1_asn_lookup()
KEYS: trusted: Change -EINVAL to -E2BIG
KEYS: trusted: Move tpm2_key_decode() to the TPM driver
tpm: tpm2_key: Extend parser to TPM_LoadableKey

crypto/asymmetric_keys/Kconfig | 15 +
crypto/asymmetric_keys/Makefile | 1 +
crypto/asymmetric_keys/tpm2_key_rsa.c | 670 ++++++++++++++++++
crypto/rsa-pkcs1pad.c | 16 +-
drivers/char/tpm/Kconfig | 1 +
drivers/char/tpm/Makefile | 5 +
drivers/char/tpm/tpm2_key.c | 118 +++
.../char/tpm}/tpm2key.asn1 | 0
include/crypto/rsa-pkcs1pad.h | 20 +
include/crypto/tpm2_key.h | 35 +
include/linux/tpm.h | 2 +
security/keys/trusted-keys/Makefile | 2 -
security/keys/trusted-keys/trusted_tpm2.c | 131 +---
13 files changed, 898 insertions(+), 118 deletions(-)
create mode 100644 crypto/asymmetric_keys/tpm2_key_rsa.c
create mode 100644 drivers/char/tpm/tpm2_key.c
rename {security/keys/trusted-keys => drivers/char/tpm}/tpm2key.asn1 (100%)
create mode 100644 include/crypto/rsa-pkcs1pad.h
create mode 100644 include/crypto/tpm2_key.h

--
2.45.1



2024-05-22 00:54:51

by Jarkko Sakkinen

[permalink] [raw]
Subject: [PATCH v4 3/5] KEYS: trusted: Move tpm2_key_decode() to the TPM driver

Move tpm2_key_decode() to the TPM driver and export the symbols to make
them callable from trusted keys. It can re-used for asymmetric keys.

Signed-off-by: Jarkko Sakkinen <[email protected]>
---
v2:
Do not allocate blob twice. Use the one inside struct tpm2_key.
---
drivers/char/tpm/Kconfig | 1 +
drivers/char/tpm/Makefile | 5 +
drivers/char/tpm/tpm2_key.c | 111 +++++++++++++++
.../char/tpm}/tpm2key.asn1 | 0
include/crypto/tpm2_key.h | 33 +++++
security/keys/trusted-keys/Makefile | 2 -
security/keys/trusted-keys/trusted_tpm2.c | 127 +++---------------
7 files changed, 167 insertions(+), 112 deletions(-)
create mode 100644 drivers/char/tpm/tpm2_key.c
rename {security/keys/trusted-keys => drivers/char/tpm}/tpm2key.asn1 (100%)
create mode 100644 include/crypto/tpm2_key.h

diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index e63a6a17793c..de2f4093c939 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -7,6 +7,7 @@ menuconfig TCG_TPM
tristate "TPM Hardware Support"
depends on HAS_IOMEM
imply SECURITYFS
+ select ASN1
select CRYPTO
select CRYPTO_HASH_INFO
help
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 4c695b0388f3..071437058ef6 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -17,6 +17,11 @@ tpm-y += eventlog/tpm1.o
tpm-y += eventlog/tpm2.o
tpm-y += tpm-buf.o

+# TPM2 Asymmetric Key
+$(obj)/trusted_tpm2.o: $(obj)/tpm2key.asn1.h
+tpm-y += tpm2key.asn1.o
+tpm-y += tpm2_key.o
+
tpm-$(CONFIG_TCG_TPM2_HMAC) += tpm2-sessions.o
tpm-$(CONFIG_ACPI) += tpm_ppi.o eventlog/acpi.o
tpm-$(CONFIG_EFI) += eventlog/efi.o
diff --git a/drivers/char/tpm/tpm2_key.c b/drivers/char/tpm/tpm2_key.c
new file mode 100644
index 000000000000..7662b2cb85bf
--- /dev/null
+++ b/drivers/char/tpm/tpm2_key.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/oid_registry.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <crypto/tpm2_key.h>
+#include <asm/unaligned.h>
+#include "tpm2key.asn1.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt) "tpm2_key: "fmt
+
+int tpm2_key_parent(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct tpm2_key *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 *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 *ctx = context;
+
+ ctx->priv = value;
+ ctx->priv_len = vlen;
+
+ return 0;
+}
+
+/**
+ * tpm_key_decode() - Decode TPM2 ASN.1 key.
+ * @src: ASN.1 source.
+ * @src_len: ASN.1 source length.
+ * @key: TPM2 asymmetric key.
+ * @max_key_len: Cap the maximum length for the blob allocation.
+ *
+ * Decodes TPM2 ASN.1 key on success. Returns POSIX error code on failure.
+ */
+int tpm2_key_decode(const u8 *src, u32 src_len, struct tpm2_key *key,
+ u32 max_key_len)
+{
+ struct tpm2_key ctx;
+ u32 blob_len;
+ int ret;
+
+ memset(&ctx, 0, sizeof(ctx));
+
+ ret = asn1_ber_decoder(&tpm2key_decoder, &ctx, src, src_len);
+ if (ret < 0)
+ return ret;
+
+ blob_len = ctx.priv_len + ctx.pub_len;
+ if (blob_len > max_key_len)
+ return -E2BIG;
+
+ ctx.blob_len = blob_len;
+ ctx.blob = kmalloc(blob_len, GFP_KERNEL);
+ if (!ctx.blob)
+ return -ENOMEM;
+
+ memcpy((void *)ctx.blob, ctx.priv, ctx.priv_len);
+ memcpy((void *)ctx.blob + ctx.priv_len, ctx.pub, ctx.pub_len);
+ ctx.priv = ctx.blob;
+ ctx.pub = ctx.blob + ctx.priv_len;
+
+ memcpy(key, &ctx, sizeof(ctx));
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tpm2_key_decode);
diff --git a/security/keys/trusted-keys/tpm2key.asn1 b/drivers/char/tpm/tpm2key.asn1
similarity index 100%
rename from security/keys/trusted-keys/tpm2key.asn1
rename to drivers/char/tpm/tpm2key.asn1
diff --git a/include/crypto/tpm2_key.h b/include/crypto/tpm2_key.h
new file mode 100644
index 000000000000..acf41b2e0c92
--- /dev/null
+++ b/include/crypto/tpm2_key.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __LINUX_TPM2_KEY_H__
+#define __LINUX_TPM2_KEY_H__
+
+#include <linux/slab.h>
+
+/*
+ * TPM2 ASN.1 key
+ */
+struct tpm2_key {
+ u32 parent;
+ const u8 *blob;
+ u32 blob_len;
+ const u8 *pub;
+ u32 pub_len;
+ const u8 *priv;
+ u32 priv_len;
+};
+
+int tpm2_key_decode(const u8 *src, u32 src_len, struct tpm2_key *key,
+ u32 max_key_len);
+
+/**
+ * tpm2_key_free() - Release TPM2 asymmetric key resources and reset values
+ * @key: TPM2 asymmetric key.
+ */
+static inline void tpm2_key_destroy(struct tpm2_key *key)
+{
+ kfree(key->blob);
+ memset(key, 0, sizeof(*key));
+}
+
+#endif /* __LINUX_TPM2_KEY_H__ */
diff --git a/security/keys/trusted-keys/Makefile b/security/keys/trusted-keys/Makefile
index f0f3b27f688b..2674d5c10fc9 100644
--- a/security/keys/trusted-keys/Makefile
+++ b/security/keys/trusted-keys/Makefile
@@ -7,9 +7,7 @@ obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
trusted-y += trusted_core.o
trusted-$(CONFIG_TRUSTED_KEYS_TPM) += trusted_tpm1.o

-$(obj)/trusted_tpm2.o: $(obj)/tpm2key.asn1.h
trusted-$(CONFIG_TRUSTED_KEYS_TPM) += trusted_tpm2.o
-trusted-$(CONFIG_TRUSTED_KEYS_TPM) += tpm2key.asn1.o

trusted-$(CONFIG_TRUSTED_KEYS_TEE) += trusted_tee.o

diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index 06c8fa7b21ae..7e6eaec8b0bc 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -13,11 +13,10 @@

#include <keys/trusted-type.h>
#include <keys/trusted_tpm.h>
+#include <crypto/tpm2_key.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},
@@ -28,9 +27,9 @@ static struct tpm2_hash tpm2_hash_map[] = {

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)
+static int tpm2_trusted_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);
@@ -98,106 +97,6 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
return ret;
}

-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 -E2BIG;
-
- 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;
-}
-
/**
* tpm2_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer.
*
@@ -347,7 +246,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
goto out;
}

- blob_len = tpm2_key_encode(payload, options, &buf.data[offset], blob_len);
+ blob_len = tpm2_trusted_key_encode(payload, options, &buf.data[offset],
+ blob_len);

out:
tpm_buf_destroy(&sized);
@@ -387,21 +287,27 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
struct trusted_key_options *options,
u32 *blob_handle)
{
- struct tpm_buf buf;
unsigned int private_len;
unsigned int public_len;
unsigned int blob_len;
- u8 *blob, *pub;
+ struct tpm2_key key;
+ struct tpm_buf buf;
+ const u8 *blob, *pub;
int rc;
u32 attrs;

- rc = tpm2_key_decode(payload, options, &blob);
+ rc = tpm2_key_decode(payload->blob, payload->blob_len, &key, PAGE_SIZE);
if (rc) {
/* old form */
blob = payload->blob;
payload->old_format = 1;
+ } else {
+ blob = key.blob;
}

+ if (!blob)
+ return -ENOMEM;
+
/* new format carries keyhandle but old format doesn't */
if (!options->keyhandle)
return -EINVAL;
@@ -465,7 +371,8 @@ static int tpm2_load_cmd(struct tpm_chip *chip,

out:
if (blob != payload->blob)
- kfree(blob);
+ tpm2_key_destroy(&key);
+
tpm_buf_destroy(&buf);

if (rc > 0)
--
2.45.1