tpm2-tools/0002-tpm2_encodeobject-New-tool-to-encode-TPM2-object.patch
Štěpán Horáček 53479d9612 tpm2-tools: Backport from upstream
Includes fixes and tpm2_encodeobject tool.

Resolves: rhbz#2160304
Resolves: rhbz#2047342

Signed-off-by: Štěpán Horáček <shoracek@redhat.com>
2023-06-05 17:36:15 +02:00

386 lines
10 KiB
Diff

From ba7682dc511f4ef6bbb8a15ca3bb0edf67ec39ce Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Fri, 17 Sep 2021 07:14:20 +0200
Subject: [PATCH 02/17] tpm2_encodeobject: New tool to encode TPM2 object
This adds a new tool tpm2_encodeobject in tools/misc. It takes
public and private portions of an object and encode them in a combined
PEM form used by tpm2-tss-engine and other applications.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
Makefile.am | 2 +
man/tpm2_encodeobject.1.md | 92 +++++++++++++
tools/misc/tpm2_encodeobject.c | 240 +++++++++++++++++++++++++++++++++
3 files changed, 334 insertions(+)
create mode 100644 man/tpm2_encodeobject.1.md
create mode 100644 tools/misc/tpm2_encodeobject.c
diff --git a/Makefile.am b/Makefile.am
index 71322159..e1a51ebf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -103,6 +103,7 @@ tools_tpm2_SOURCES = \
tpm2_tools = \
tools/misc/tpm2_certifyX509certutil.c \
tools/misc/tpm2_checkquote.c \
+ tools/misc/tpm2_encodeobject.c \
tools/misc/tpm2_eventlog.c \
tools/misc/tpm2_print.c \
tools/misc/tpm2_rc_decode.c \
@@ -376,6 +377,7 @@ if HAVE_MAN_PAGES
man/man1/tpm2_createprimary.1 \
man/man1/tpm2_dictionarylockout.1 \
man/man1/tpm2_duplicate.1 \
+ man/man1/tpm2_encodeobject.1 \
man/man1/tpm2_getcap.1 \
man/man1/tpm2_encryptdecrypt.1 \
man/man1/tpm2_eventlog.1 \
diff --git a/man/tpm2_encodeobject.1.md b/man/tpm2_encodeobject.1.md
new file mode 100644
index 00000000..791eafbd
--- /dev/null
+++ b/man/tpm2_encodeobject.1.md
@@ -0,0 +1,92 @@
+% tpm2_encodeobject(1) tpm2-tools | General Commands Manual
+
+# NAME
+
+**tpm2_encodeobject**(1) - Encode an object into a combined PEM format.
+
+# SYNOPSIS
+
+**tpm2_encodeobject** [*OPTIONS*]
+
+# DESCRIPTION
+
+**tpm2_encodeobject**(1) - Encode both the private and public portions of an
+object into a combined PEM format used by tpm2-tss-engine.
+
+The tool reads private and public portions of an object and encodes it
+into a combined PEM format used by tpm2-tss-engine and other
+applications.
+
+**NOTE**: Both private and public portions of the tpm key must be specified.
+
+# OPTIONS
+
+ * **-C**, **\--parent-context**=_OBJECT_:
+
+ The parent object.
+
+ * **-P**, **\--auth**=_AUTH_:
+
+ The authorization value of the parent object specified by **-C**.
+
+ * **-u**, **\--public**=_FILE_:
+
+ A file containing the public portion of the object.
+
+ * **-r**, **\--private**=_FILE_:
+
+ A file containing the sensitive portion of the object.
+
+ * **-o**, **\--output**=_FILE_:
+
+ The output file path, recording the public portion of the object.
+
+## References
+
+[context object format](common/ctxobj.md) details the methods for specifying
+_OBJECT_.
+
+[authorization formatting](common/authorizations.md) details the methods for
+specifying _AUTH_.
+
+[common options](common/options.md) collection of common options that provide
+information many users may expect.
+
+[common tcti options](common/tcti.md) collection of options used to configure
+the various known TCTI modules.
+
+# EXAMPLES
+
+## Setup
+To load an object you first must create an object under a primary object. So the
+first step is to create the primary object.
+
+```bash
+tpm2_createprimary -c primary.ctx
+```
+
+Step 2 is to create an object under the primary object.
+
+```bash
+tpm2_create -C primary.ctx -u key.pub -r key.priv -f pem -o pub.pem
+```
+
+This creates the private and public portions of the TPM object. With these
+object portions, it is now possible to load that object into the TPM for
+subsequent use.
+
+## Encoding an Object into a combined PEM format
+
+The final step, is encoding the public and private portions of the object into a
+PEM format.
+
+```bash
+tpm2_encodeobject -C primary.ctx -u key.pub -r key.priv -c priv.pem
+```
+
+The generated `priv.pem` can be used together with `pub.pem` created in the
+step 2 of Setup section.
+
+[returns](common/returns.md)
+
+[footer](common/footer.md)
diff --git a/tools/misc/tpm2_encodeobject.c b/tools/misc/tpm2_encodeobject.c
new file mode 100644
index 00000000..2341c3a1
--- /dev/null
+++ b/tools/misc/tpm2_encodeobject.c
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+/*
+ * Part of this file is copied from tpm2-tss-engine.
+ *
+ * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
+ * All rights reserved.
+ * Copyright (c) 2019, Wind River Systems.
+ * All rights reserved.
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <tss2/tss2_mu.h>
+
+#include "files.h"
+#include "log.h"
+#include "tpm2.h"
+#include "tpm2_options.h"
+#include "tpm2_tool.h"
+
+#define OID_loadableKey "2.23.133.10.1.3"
+
+typedef struct {
+ ASN1_OBJECT *type;
+ ASN1_BOOLEAN emptyAuth;
+ ASN1_INTEGER *parent;
+ ASN1_OCTET_STRING *pubkey;
+ ASN1_OCTET_STRING *privkey;
+} TSSPRIVKEY;
+
+DECLARE_ASN1_FUNCTIONS(TSSPRIVKEY);
+DECLARE_PEM_write_bio(TSSPRIVKEY, TSSPRIVKEY);
+
+ASN1_SEQUENCE(TSSPRIVKEY) = {
+ ASN1_SIMPLE(TSSPRIVKEY, type, ASN1_OBJECT),
+ ASN1_EXP_OPT(TSSPRIVKEY, emptyAuth, ASN1_BOOLEAN, 0),
+ ASN1_SIMPLE(TSSPRIVKEY, parent, ASN1_INTEGER),
+ ASN1_SIMPLE(TSSPRIVKEY, pubkey, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(TSSPRIVKEY, privkey, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(TSSPRIVKEY)
+
+#define TSSPRIVKEY_PEM_STRING "TSS2 PRIVATE KEY"
+
+IMPLEMENT_ASN1_FUNCTIONS(TSSPRIVKEY);
+IMPLEMENT_PEM_write_bio(TSSPRIVKEY, TSSPRIVKEY, TSSPRIVKEY_PEM_STRING, TSSPRIVKEY);
+IMPLEMENT_PEM_read_bio(TSSPRIVKEY, TSSPRIVKEY, TSSPRIVKEY_PEM_STRING, TSSPRIVKEY);
+
+typedef struct tpm_encodeobject_ctx tpm_encodeobject_ctx;
+struct tpm_encodeobject_ctx {
+ struct {
+ const char *ctx_path;
+ const char *auth_str;
+ tpm2_loaded_object object;
+ } parent;
+
+ struct {
+ const char *pubpath;
+ TPM2B_PUBLIC public;
+ const char *privpath;
+ TPM2B_PRIVATE private;
+ ESYS_TR handle;
+ } object;
+
+ char *output_path;
+};
+
+static tpm_encodeobject_ctx ctx;
+
+static bool on_option(char key, char *value) {
+ switch (key) {
+ case 'P':
+ ctx.parent.auth_str = value;
+ break;
+ case 'u':
+ ctx.object.pubpath = value;
+ break;
+ case 'r':
+ ctx.object.privpath = value;
+ break;
+ case 'C':
+ ctx.parent.ctx_path = value;
+ break;
+ case 'o':
+ ctx.output_path = value;
+ break;
+ }
+
+ return true;
+}
+
+static bool tpm2_tool_onstart(tpm2_options **opts) {
+ const struct option topts[] = {
+ { "auth", required_argument, NULL, 'P' },
+ { "public", required_argument, NULL, 'u' },
+ { "private", required_argument, NULL, 'r' },
+ { "parent-context", required_argument, NULL, 'C' },
+ { "output", required_argument, NULL, 'o' },
+ };
+
+ *opts = tpm2_options_new("P:u:r:C:o:", ARRAY_LEN(topts), topts, on_option,
+ NULL, 0);
+
+ return *opts != NULL;
+}
+
+static tool_rc check_opts(void) {
+ tool_rc rc = tool_rc_success;
+ if (!ctx.parent.ctx_path) {
+ LOG_ERR("Expected parent object via -C");
+ rc = tool_rc_option_error;
+ }
+
+ if (!ctx.object.pubpath) {
+ LOG_ERR("Expected public object portion via -u");
+ rc = tool_rc_option_error;
+ }
+
+ if (!ctx.object.privpath) {
+ LOG_ERR("Expected private object portion via -r");
+ rc = tool_rc_option_error;
+ }
+
+ if (!ctx.output_path) {
+ LOG_ERR("Expected output file path via -o");
+ rc = tool_rc_option_error;
+ }
+
+ return rc;
+}
+
+static tool_rc init(ESYS_CONTEXT *ectx) {
+ bool res = files_load_public(ctx.object.pubpath, &ctx.object.public);
+ if (!res) {
+ return tool_rc_general_error;
+ }
+
+ res = files_load_private(ctx.object.privpath, &ctx.object.private);
+ if (!res) {
+ return tool_rc_general_error;
+ }
+
+ return tpm2_util_object_load_auth(ectx, ctx.parent.ctx_path,
+ ctx.parent.auth_str, &ctx.parent.object, false,
+ TPM2_HANDLE_ALL_W_NV);
+}
+
+static int
+encode(void)
+{
+ TSS2_RC rc;
+ BIO *bio = NULL;
+ TSSPRIVKEY *tpk = NULL;
+
+ uint8_t private_buf[sizeof(ctx.object.private)];
+ uint8_t public_buf[sizeof(ctx.object.public)];
+ size_t private_len = 0, public_len = 0;
+
+ rc = Tss2_MU_TPM2B_PRIVATE_Marshal(&ctx.object.private, private_buf,
+ sizeof(private_buf), &private_len);
+ if (rc) {
+ LOG_ERR("Error serializing private portion of object");
+ goto error;
+ }
+
+ rc = Tss2_MU_TPM2B_PUBLIC_Marshal(&ctx.object.public, public_buf,
+ sizeof(public_buf), &public_len);
+ if (rc) {
+ LOG_ERR("Error serializing public portion of object");
+ goto error;
+ }
+
+ tpk = TSSPRIVKEY_new();
+ if (!tpk) {
+ LOG_ERR("oom");
+ goto error;
+ }
+
+ tpk->type = OBJ_txt2obj(OID_loadableKey, 1);
+ tpk->parent = ASN1_INTEGER_new();
+ tpk->privkey = ASN1_OCTET_STRING_new();
+ tpk->pubkey = ASN1_OCTET_STRING_new();
+ if (!tpk->type || !tpk->privkey || !tpk->pubkey || !tpk->parent) {
+ LOG_ERR("oom");
+ goto error;
+ }
+
+ tpk->emptyAuth = ctx.parent.auth_str == NULL ? 0xFF : 0;
+
+ if ((ctx.parent.object.handle >> TPM2_HR_SHIFT) == TPM2_HT_PERSISTENT) {
+ ASN1_INTEGER_set(tpk->parent, ctx.parent.object.handle);
+ } else {
+ /* Indicate that the parent is a primary object generated on the fly. */
+ ASN1_INTEGER_set(tpk->parent, TPM2_RH_OWNER);
+ }
+
+ ASN1_STRING_set(tpk->privkey, private_buf, private_len);
+ ASN1_STRING_set(tpk->pubkey, public_buf, public_len);
+
+ if ((bio = BIO_new_file(ctx.output_path, "w")) == NULL) {
+ LOG_ERR("Could not open file: \"%s\"", ctx.output_path);
+ goto error;
+ }
+
+ PEM_write_bio_TSSPRIVKEY(bio, tpk);
+ TSSPRIVKEY_free(tpk);
+ BIO_free(bio);
+
+ return tool_rc_success;
+ error:
+ if (bio)
+ BIO_free(bio);
+ if (tpk)
+ TSSPRIVKEY_free(tpk);
+ return tool_rc_general_error;
+}
+
+static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *ectx, tpm2_option_flags flags) {
+ UNUSED(flags);
+
+ tool_rc rc = check_opts();
+ if (rc != tool_rc_success) {
+ return rc;
+ }
+
+ rc = init(ectx);
+ if (rc != tool_rc_success) {
+ return rc;
+ }
+
+ return encode();
+}
+
+// Register this tool with tpm2_tool.c
+TPM2_TOOL_REGISTER("encodeobject", tpm2_tool_onstart, tpm2_tool_onrun, NULL, NULL)
--
2.40.1