aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2020-01-02 16:00:53 -0800
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2020-01-26 08:50:43 -0800
commit84c3e0add62096e37fa0cd41f95e3d625c67c8f2 (patch)
tree6632036e172f8eb5de51411a5c59f31bf5525c1e
parent600da197e76940cfd654519734125131f6964798 (diff)
downloadopenssl_tpm2_engine-84c3e0add62096e37fa0cd41f95e3d625c67c8f2.tar.gz
Add TPM data sealing and unsealing functions
This adds two commands and their manpages: seal_tpm2_data and unseal_tpm2_data plus a new OID 2.23.133.10.1.5 to identify sealed data. The object is to be interoperable with the new kernel sealed data format. Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r--.gitignore2
-rw-r--r--Makefile.am16
-rw-r--r--e_tpm2-ecc.c2
-rw-r--r--e_tpm2-rsa.c2
-rw-r--r--load_tpm2_key.c2
-rw-r--r--seal_tpm2_data.1.in18
-rw-r--r--seal_tpm2_data.c337
-rw-r--r--tpm2-asn.h2
-rw-r--r--tpm2-common.c18
-rw-r--r--tpm2-common.h2
-rw-r--r--unseal_tpm2_data.1.in18
-rw-r--r--unseal_tpm2_data.c206
12 files changed, 612 insertions, 13 deletions
diff --git a/.gitignore b/.gitignore
index 9eca341..48f9458 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,8 @@ ltmain.sh
missing
create_tpm2_key
load_tpm2_key
+seal_tpm2_data
+unseal_tpm2_data
test-driver
tests/*.log
tests/*.trs
diff --git a/Makefile.am b/Makefile.am
index 734bfc5..33de0d9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,14 +1,16 @@
EXTRA_DIST = README openssl.cnf.sample
if NATIVE_BUILD
-EXTRA_DIST += create_tpm2_key.1 load_tpm2_key.1
-man1_MANS = create_tpm2_key.1 load_tpm2_key.1
+EXTRA_DIST += create_tpm2_key.1 load_tpm2_key.1 seal_tpm2_data.1 \
+ unseal_tpm2_data.1
+man1_MANS = create_tpm2_key.1 load_tpm2_key.1 seal_tpm2_data.1 \
+ unseal_tpm2_data.1
CLEANFILES = $(man1_MANS)
endif
openssl_engine_LTLIBRARIES=libtpm2.la
-bin_PROGRAMS=create_tpm2_key load_tpm2_key
+bin_PROGRAMS=create_tpm2_key load_tpm2_key seal_tpm2_data unseal_tpm2_data
openssl_enginedir=@enginesdir@
libtpm2_la_LDFLAGS= -no-undefined -avoid-version
@@ -24,6 +26,14 @@ load_tpm2_key_SOURCES=load_tpm2_key.c tpm2-common.c
load_tpm2_key_LDADD=${DEPS_LIBS}
load_tpm2_key_CFLAGS=${DEPS_CFLAGS} -Werror
+seal_tpm2_data_SOURCES=seal_tpm2_data.c tpm2-common.c
+seal_tpm2_data_LDADD=${DEPS_LIBS}
+seal_tpm2_data_CFLAGS=${DEPS_CFLAGS} -Werror
+
+unseal_tpm2_data_SOURCES=unseal_tpm2_data.c tpm2-common.c
+unseal_tpm2_data_LDADD=${DEPS_LIBS}
+unseal_tpm2_data_CFLAGS=${DEPS_CFLAGS} -Werror
+
$(builddir)/%.1: $(srcdir)/%.1.in $(top_builddir)/%
$(HELP2MAN) --no-info -i $< -o $@ $(top_builddir)/$*
diff --git a/e_tpm2-ecc.c b/e_tpm2-ecc.c
index 89e3762..0e4c905 100644
--- a/e_tpm2-ecc.c
+++ b/e_tpm2-ecc.c
@@ -87,7 +87,7 @@ static TPM_HANDLE tpm2_load_key_from_ecc(const EC_KEY *eck,
*num_commands = app_data->num_commands;
*nameAlg = app_data->name_alg;
- return tpm2_load_key(tssContext, app_data, srk_auth);
+ return tpm2_load_key(tssContext, app_data, srk_auth, NULL);
}
void tpm2_bind_key_to_engine_ecc(EVP_PKEY *pkey, void *data)
diff --git a/e_tpm2-rsa.c b/e_tpm2-rsa.c
index 85be4a8..07fb075 100644
--- a/e_tpm2-rsa.c
+++ b/e_tpm2-rsa.c
@@ -119,7 +119,7 @@ static TPM_HANDLE tpm2_load_key_from_rsa(RSA *rsa, TSS_CONTEXT **tssContext,
*num_commands = app_data->num_commands;
*nameAlg = app_data->name_alg;
- return tpm2_load_key(tssContext, app_data, srk_auth);
+ return tpm2_load_key(tssContext, app_data, srk_auth, NULL);
}
void tpm2_bind_key_to_engine_rsa(EVP_PKEY *pkey, void *data)
diff --git a/load_tpm2_key.c b/load_tpm2_key.c
index 244c9dc..defc1c4 100644
--- a/load_tpm2_key.c
+++ b/load_tpm2_key.c
@@ -148,7 +148,7 @@ int main(int argc, char **argv)
goto out_free;
}
- ret = tpm2_load_key(&tssContext, app_data, auth);
+ ret = tpm2_load_key(&tssContext, app_data, auth, NULL);
if (!ret) {
ret = 1;
goto out;
diff --git a/seal_tpm2_data.1.in b/seal_tpm2_data.1.in
new file mode 100644
index 0000000..b88510a
--- /dev/null
+++ b/seal_tpm2_data.1.in
@@ -0,0 +1,18 @@
+[name]
+seal_tpm2_data - seal a blob of data for a TPM
+
+[description]
+
+Used to create a sealed blob of data which can be unsealed via the
+TPM. Possible uses for this blob of data include as a symmetric key,
+which is the use in the linux kernel trusted key infrastructure.
+
+[examples]
+
+Create a sealed data blob to the storage parent (owner hierarchy)
+
+ echo somedatatoseal | seal_tpm2_key -p owner seal.tpm
+
+Unseal the data
+
+ unseal_tpm2_key seal.tpm
diff --git a/seal_tpm2_data.c b/seal_tpm2_data.c
new file mode 100644
index 0000000..a04f878
--- /dev/null
+++ b/seal_tpm2_data.c
@@ -0,0 +1,337 @@
+/*
+ *
+ * Copyright (C) 2019 James Bottomley <James.Bottomley@HansenPartnership.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ */
+
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/ui.h>
+
+#define TSSINCLUDE(x) < TSS_INCLUDE/x >
+#include TSSINCLUDE(tss.h)
+#include TSSINCLUDE(tssutils.h)
+#include TSSINCLUDE(tssmarshal.h)
+#include TSSINCLUDE(Unmarshal_fp.h)
+#include TSSINCLUDE(tsscrypto.h)
+#include TSSINCLUDE(tsscryptoh.h)
+
+#include "tpm2-asn.h"
+#include "tpm2-common.h"
+
+static TPM_ALG_ID name_alg = TPM_ALG_SHA256;
+
+static struct option long_options[] = {
+ {"auth", 0, 0, 'a'},
+ {"auth-parent", 1, 0, 'b'},
+ {"help", 0, 0, 'h'},
+ {"parent-handle", 1, 0, 'p'},
+ {"version", 0, 0, 'v'},
+ {"password", 1, 0, 'k'},
+ {"da", 0, 0, 'd'},
+ {"policy", 1, 0, 'c'},
+ {"nomigrate", 0, 0, 'm'},
+ {"name-scheme", 1, 0, 'n'},
+ {0, 0, 0, 0}
+};
+
+static void tpm2_public_template_seal(TPMT_PUBLIC *pub)
+{
+ pub->type = TPM_ALG_KEYEDHASH;
+ pub->nameAlg = name_alg;
+ pub->objectAttributes.val =
+ TPMA_OBJECT_USERWITHAUTH;
+ pub->authPolicy.t.size = 0;
+ pub->parameters.keyedHashDetail.scheme.scheme = TPM_ALG_NULL;
+ pub->unique.sym.t.size = 0;
+}
+
+void
+usage(char *argv0)
+{
+ fprintf(stdout, "Usage: %s [options] <filename>\n\n"
+ "Options:\n"
+ "\t-a, --auth The data blob requires authorization\n"
+ "\t-b, --auth-parent <pwd> Specify the parent key password\n"
+ "\t (default EmptyAuth)\n"
+ "\t-d, --da mark the key as having Dictionary Attack implications. This means that if\n"
+ "\t the key password is incorrectly presented too many times, the TPM may\n"
+ "\t Implement DA mitigation and refuse connections for a while\n"
+ "\t-h, --help print this help message\n"
+ "\t-p, --parent-handle <handle> parent for the key, can either be a\n"
+ "\t persistent key or a hierarchy.\n"
+ "\t the hierarchies can be 'platform',\n"
+ "\t 'owner', 'null' or 'endorsement'.\n"
+ "\t The seeds used for derivation are\n"
+ "\t platform, storage, null or endorsement\n"
+ "\t respectively\n"
+ "\t-v, --version print package version\n"
+ "\t-k, --password <pwd> use this password instead of prompting\n"
+ "\t-m,--nomigrate Create a sealed data bundle that can be\n"
+ " migrated to other systems.\n"
+ "\t-n, --name-scheme <scheme> name algorithm to use sha1 [sha256] sha384 sha512\n"
+ "\n"
+ "Report bugs to " PACKAGE_BUGREPORT "\n",
+ argv0);
+ exit(-1);
+}
+
+int main(int argc, char **argv)
+{
+ int option_index, c;
+ int nomigrate = 0, parent = TPM_RH_OWNER;
+ char *data_auth = NULL, *parent_auth = NULL, *pass = NULL;
+ char *policyFilename = NULL;
+ char *filename;
+ uint32_t noda = TPMA_OBJECT_NODA, phandle;
+ TPM_RC rc;
+ TSS_CONTEXT *tssContext;
+ const char *dir;
+ const char *reason;
+ TPMT_HA digest;
+ uint32_t sizeInBytes;
+ TPM_HANDLE authHandle;
+ STACK_OF(TSSOPTPOLICY) *sk = NULL;
+ Create_In cin;
+ Create_Out cout;
+ TPMS_SENSITIVE_CREATE *s = &cin.inSensitive.sensitive;
+ TPMT_PUBLIC *p = &cin.inPublic.publicArea;
+ BYTE pubkey[sizeof(TPM2B_PUBLIC)];
+ BYTE privkey[sizeof(TPM2B_PRIVATE)];
+ BYTE *buffer;
+ int32_t size;
+ uint16_t pubkey_len, privkey_len;
+
+ while (1) {
+ option_index = 0;
+ c = getopt_long(argc, argv, "ak:b:hp:vdsun",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'a':
+ data_auth = malloc(128);
+ break;
+ case 'k':
+ pass = optarg;
+ if (strlen(pass) > 127) {
+ printf("password is too long\n");
+ exit(1);
+ }
+ break;
+ case 'b':
+ parent_auth = optarg;
+ break;
+ case 'h':
+ usage(argv[0]);
+ break;
+ case 'n':
+ if (!strcasecmp("sha1", optarg)) {
+ name_alg = TPM_ALG_SHA1;
+ } else if (!strcasecmp("sha256", optarg)) {
+ /* default, do nothing */
+ } else if (!strcasecmp("sha384", optarg)) {
+ name_alg = TPM_ALG_SHA384;
+#ifdef TPM_ALG_SHA512
+ } else if (!strcasecmp("sha512", optarg)) {
+ name_alg = TPM_ALG_SHA512;
+#endif
+ } else {
+ usage(argv[0]);
+ }
+ break;
+ case 'p':
+ parent = tpm2_get_parent(optarg);
+ if (parent == 0) {
+ fprintf(stderr, "Invalid parent %s\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'v':
+ fprintf(stdout, "%s " VERSION "\n"
+ "Copyright 2017 by James Bottomley\n"
+ "License LGPL-2.1-only\n"
+ "Written by James Bottomley <James.Bottomley@HansenPartnership.com>\n",
+ argv[0]);
+ exit(0);
+ case 'd':
+ noda = 0;
+ break;
+ case 'c':
+ policyFilename = optarg;
+ break;
+ case 'm':
+ nomigrate = 1;
+ break;
+ default:
+ printf("Unknown option '%c'\n", c);
+ usage(argv[0]);
+ break;
+ }
+ }
+ if (optind >= argc) {
+ printf("Too few arguments: Expected file name as last argument\n");
+ usage(argv[0]);
+ }
+
+ filename = argv[argc - 1];
+
+ if (optind < argc - 1) {
+ printf("Unexpected additional arguments\n");
+ usage(argv[0]);
+ }
+
+ digest.hashAlg = name_alg;
+ sizeInBytes = TSS_GetDigestSize(digest.hashAlg);
+ memset((uint8_t *)&digest.digest, 0, sizeInBytes);
+
+ if (policyFilename) {
+ sk = sk_TSSOPTPOLICY_new_null();
+ if (!sk) {
+ fprintf(stderr, "Failed to allocate policy stack\n");
+ exit(1);
+ }
+
+ rc = tpm2_parse_policy_file(policyFilename, sk,
+ data_auth, &digest);
+ if (rc) {
+ reason = "parse_policy_file";
+ goto out_free_policy;
+ }
+ }
+
+ if (data_auth) {
+ if (pass) {
+ /* key length already checked */
+ strcpy(data_auth, pass);
+ } else {
+ if (EVP_read_pw_string(data_auth, 128,
+ "Enter TPM key authority: ", 1)) {
+ fprintf(stderr, "Passwords do not match\n");
+ reason = "authorization";
+ rc = NOT_TPM_ERROR;
+ goto out_free_auth;
+ }
+ }
+ }
+
+ dir = tpm2_set_unique_tssdir();
+ rc = tpm2_create(&tssContext, dir);
+ if (rc) {
+ reason = "TSS_Create";
+ goto out_rmdir;
+ }
+
+ if ((parent & 0xff000000) == 0x40000000) {
+ rc = tpm2_load_srk(tssContext, &phandle, parent_auth,
+ NULL, parent, 1);
+ if (rc) {
+ reason = "tpm2_load_srk";
+ goto out_delete;
+ }
+ } else {
+ phandle = parent;
+ }
+
+ tpm2_public_template_seal(p);
+
+ cin.parentHandle = phandle;
+ cin.outsideInfo.t.size = 0;
+ cin.creationPCR.count = 0;
+
+ if (policyFilename) {
+ p->objectAttributes.val &=
+ ~TPMA_OBJECT_USERWITHAUTH;
+ rc = TSS_TPM2B_Create(
+ &p->authPolicy.b,
+ (uint8_t *)&digest.digest, sizeInBytes,
+ sizeof(TPMU_HA));
+ if (rc) {
+ reason = "set policy";
+ goto out_flush;
+ }
+ }
+
+ memset(s, 0, sizeof(*s));
+ if (data_auth) {
+ int len = strlen(data_auth);
+ memcpy(s->userAuth.b.buffer, data_auth, len);
+ s->userAuth.b.size = len;
+ }
+ s->data.t.size = fread(s->data.t.buffer, 1,
+ MAX_SYM_DATA, stdin);
+
+ /* set the NODA flag */
+ p->objectAttributes.val |= noda;
+
+ if (nomigrate)
+ p->objectAttributes.val |=
+ TPMA_OBJECT_FIXEDPARENT |
+ TPMA_OBJECT_FIXEDTPM;
+
+ /* use salted parameter encryption to hide the key */
+ rc = tpm2_get_session_handle(tssContext, &authHandle, phandle,
+ TPM_SE_HMAC, name_alg);
+ if (rc) {
+ reason = "get session handle";
+ goto out_flush;
+ }
+
+ rc = TSS_Execute(tssContext,
+ (RESPONSE_PARAMETERS *)&cout,
+ (COMMAND_PARAMETERS *)&cin,
+ NULL,
+ TPM_CC_Create,
+ authHandle, parent_auth, TPMA_SESSION_DECRYPT,
+ TPM_RH_NULL, NULL, 0);
+ if (rc) {
+ reason = "TPM2_Create";
+ /* failure means auth handle is not flushed */
+ tpm2_flush_handle(tssContext, authHandle);
+ goto out_flush;
+ }
+
+ buffer = pubkey;
+ pubkey_len = 0;
+ size = sizeof(pubkey);
+ TSS_TPM2B_PUBLIC_Marshal(&cout.outPublic, &pubkey_len,
+ &buffer, &size);
+ buffer = privkey;
+ privkey_len = 0;
+ size = sizeof(privkey);
+ TSS_TPM2B_PRIVATE_Marshal(&cout.outPrivate, &privkey_len,
+ &buffer, &size);
+ tpm2_write_tpmfile(filename, pubkey, pubkey_len,
+ privkey, privkey_len, data_auth == NULL,
+ parent, sk, 2, NULL);
+
+
+ out_flush:
+ tpm2_flush_srk(tssContext, phandle);
+ out_delete:
+ TSS_Delete(tssContext);
+ out_rmdir:
+ rmdir(dir);
+ out_free_auth:
+ free(data_auth);
+ out_free_policy:
+ tpm2_free_policy(sk);
+
+ if (rc) {
+ if (rc == NOT_TPM_ERROR)
+ fprintf(stderr, "%s failed\n", reason);
+ else
+ tpm2_error(rc, reason);
+ rc = 1;
+ }
+ exit(rc);
+}
diff --git a/tpm2-asn.h b/tpm2-asn.h
index 9afa7c3..93a97fc 100644
--- a/tpm2-asn.h
+++ b/tpm2-asn.h
@@ -98,7 +98,7 @@ typedef struct {
#define OID_loadableKey "2.23.133.10.1.3"
#define OID_importableKey "2.23.133.10.1.4"
-
+#define OID_sealedData "2.23.133.10.1.5"
/* This is the PEM guard tag */
#define TSSLOADABLE_PEM_STRING "TSS2 KEY BLOB"
diff --git a/tpm2-common.c b/tpm2-common.c
index 95d5f7e..f346585 100644
--- a/tpm2-common.c
+++ b/tpm2-common.c
@@ -1117,6 +1117,8 @@ int tpm2_load_engine_file(const char *filename, struct app_data **app_data,
goto err;
}
tpm2_type = TPM2_IMPORTABLE;
+ } else if (strcmp(OID_sealedData, oid) == 0){
+ tpm2_type = TPM2_SEALED;
} else {
fprintf(stderr, "Unrecognised object type\n");
goto err;
@@ -1300,7 +1302,7 @@ void tpm2_delete(struct app_data *app_data)
}
TPM_HANDLE tpm2_load_key(TSS_CONTEXT **tsscp, struct app_data *app_data,
- const char *srk_auth)
+ const char *srk_auth, uint32_t *psrk)
{
TSS_CONTEXT *tssContext;
Load_In in;
@@ -1349,17 +1351,21 @@ TPM_HANDLE tpm2_load_key(TSS_CONTEXT **tsscp, struct app_data *app_data,
if (rc) {
tpm2_error(rc, "TPM2_Load");
tpm2_flush_handle(tssContext, session);
- }
- else
+ } else {
key = out.objectHandle;
+ }
out_flush_srk:
- tpm2_flush_srk(tssContext, in.parentHandle);
+ if (key && psrk)
+ *psrk = in.parentHandle;
+ else
+ tpm2_flush_srk(tssContext, in.parentHandle);
out:
if (!key)
TSS_Delete(tssContext);
else
*tsscp = tssContext;
+
return key;
}
@@ -1428,7 +1434,9 @@ int tpm2_write_tpmfile(const char *file, BYTE *pubkey, int pubkey_len,
PEM_write_bio_TSSLOADABLE(outb, &k.tssl);
} else {
- if (secret) {
+ if (version == 2) {
+ k.tpk.type = OBJ_txt2obj(OID_sealedData, 1);
+ } else if (secret) {
k.tpk.type = OBJ_txt2obj(OID_importableKey, 1);
k.tpk.secret = ASN1_OCTET_STRING_new();
ASN1_STRING_set(k.tpk.secret, secret->t.secret,
diff --git a/tpm2-common.h b/tpm2-common.h
index 33cac4a..046761c 100644
--- a/tpm2-common.h
+++ b/tpm2-common.h
@@ -71,7 +71,7 @@ int tpm2_load_engine_file(const char *filename, struct app_data **app_data,
EVP_PKEY **ppkey, UI_METHOD *ui, void *cb_data,
const char *srk_auth, int get_key_auth);
TPM_HANDLE tpm2_load_key(TSS_CONTEXT **tsscp, struct app_data *app_data,
- const char *srk_auth);
+ const char *srk_auth, uint32_t *psession);
void tpm2_unload_key(TSS_CONTEXT *tssContext, TPM_HANDLE key);
void tpm2_delete(struct app_data *app_data);
char *tpm2_get_auth(UI_METHOD *ui, char *input_string, void *cb_data);
diff --git a/unseal_tpm2_data.1.in b/unseal_tpm2_data.1.in
new file mode 100644
index 0000000..3533f13
--- /dev/null
+++ b/unseal_tpm2_data.1.in
@@ -0,0 +1,18 @@
+[name]
+unseal_tpm2_data - unseal a blob of data using a TPM
+
+[description]
+
+Once a sealed data blob has been created, it may only be unsealed by
+the TPM for which it was created. This command attempts that unseal
+operation
+
+[examples]
+
+Create a sealed data blob to the storage parent (owner hierarchy)
+
+ echo "somedatatoseal" seal_tpm2_key -a -k passw0rd -p owner seal.tpm
+
+Unseal the data
+
+ unseal_tpm2_key -k passw0rd seal.tpm
diff --git a/unseal_tpm2_data.c b/unseal_tpm2_data.c
new file mode 100644
index 0000000..51f1246
--- /dev/null
+++ b/unseal_tpm2_data.c
@@ -0,0 +1,206 @@
+/*
+ *
+ * Copyright (C) 2019 James Bottomley <James.Bottomley@HansenPartnership.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ */
+
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/ui.h>
+
+#define TSSINCLUDE(x) < TSS_INCLUDE/x >
+#include TSSINCLUDE(tss.h)
+#include TSSINCLUDE(tssutils.h)
+#include TSSINCLUDE(tssmarshal.h)
+#include TSSINCLUDE(Unmarshal_fp.h)
+#include TSSINCLUDE(tsscrypto.h)
+#include TSSINCLUDE(tsscryptoh.h)
+
+#include "tpm2-asn.h"
+#include "tpm2-common.h"
+
+static TPM_ALG_ID name_alg = TPM_ALG_SHA256;
+
+static struct option long_options[] = {
+ {"auth-parent", 1, 0, 'b'},
+ {"help", 0, 0, 'h'},
+ {"version", 0, 0, 'v'},
+ {"password", 1, 0, 'k'},
+ {0, 0, 0, 0}
+};
+
+void
+usage(char *argv0)
+{
+ fprintf(stdout, "Usage: %s [options] <filename>\n\n"
+ "Options:\n"
+ "\t-b, --auth-parent <pwd> Specify the parent key password\n"
+ "\t (default EmptyAuth)\n"
+ "\t-h, --help print this help message\n"
+ "\t-v, --version print package version\n"
+ "\t-k, --password <pwd> use this password instead of prompting\n"
+ "\n"
+ "Report bugs to " PACKAGE_BUGREPORT "\n",
+ argv0);
+ exit(-1);
+}
+
+static int ui_read(UI *ui, UI_STRING *uis)
+{
+ char password[128];
+ const char *pwd = UI_get0_user_data(ui);
+
+ if (UI_get_string_type(uis) != UIT_PROMPT)
+ return 0;
+
+ if (!pwd || pwd[0] == '\0') {
+ pwd = password;
+ EVP_read_pw_string(password, sizeof(password), "TPM Sealed Data Passphrase:", 0);
+ }
+ UI_set_result(ui, uis, pwd);
+ return 1;
+}
+
+int main(int argc, char **argv)
+{
+ int option_index, c;
+ char *parent_auth = NULL, *pass = NULL;
+ char *filename;
+ TPM_RC rc;
+ TSS_CONTEXT *tssContext;
+ const char *reason;
+ Unseal_In uin;
+ Unseal_Out uout;
+ uint32_t parent, session;
+ UI_METHOD *ui = UI_create_method("unseal");
+ struct app_data *app_data;
+
+ while (1) {
+ option_index = 0;
+ c = getopt_long(argc, argv, "k:b:hv",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'k':
+ pass = optarg;
+ if (strlen(pass) > 127) {
+ printf("password is too long\n");
+ exit(1);
+ }
+ break;
+ case 'b':
+ parent_auth = optarg;
+ break;
+ case 'h':
+ usage(argv[0]);
+ break;
+ case 'v':
+ fprintf(stdout, "%s " VERSION "\n"
+ "Copyright 2017 by James Bottomley\n"
+ "License LGPL-2.1-only\n"
+ "Written by James Bottomley <James.Bottomley@HansenPartnership.com>\n",
+ argv[0]);
+ exit(0);
+ default:
+ printf("Unknown option '%c'\n", c);
+ usage(argv[0]);
+ break;
+ }
+ }
+ if (optind >= argc) {
+ printf("Too few arguments: Expected file name as last argument\n");
+ usage(argv[0]);
+ }
+
+ filename = argv[argc - 1];
+
+ if (optind < argc - 1) {
+ printf("Unexpected additional arguments\n");
+ usage(argv[0]);
+ }
+
+ if (!ui) {
+ fprintf(stderr, "Failed to allocate UI\n");
+ exit(1);
+ }
+
+ UI_method_set_reader(ui, ui_read);
+ rc = tpm2_load_engine_file(filename, &app_data, NULL,
+ ui, pass, parent_auth, 1);
+ if (!rc) {
+ reason = "tpm2_engine_load_file";
+ rc = NOT_TPM_ERROR;
+ goto err;
+ }
+
+ rc = tpm2_load_key(&tssContext, app_data, parent_auth,
+ &parent);
+ if (!rc) {
+ reason = "tpm2_load_key";
+ rc = NOT_TPM_ERROR;
+ goto out_free_app_data;
+ }
+
+ uin.itemHandle = rc;
+
+ rc = tpm2_get_session_handle(tssContext, &session, parent,
+ app_data->req_policy_session ?
+ TPM_SE_POLICY : TPM_SE_HMAC,
+ name_alg);
+ tpm2_flush_handle(tssContext, parent);
+ if (rc) {
+ reason = "tpm2_get_session_handle";
+ goto out_flush_data;
+ }
+
+ if (app_data->req_policy_session) {
+ rc = tpm2_init_session(tssContext, session,
+ app_data->num_commands,
+ app_data->commands, name_alg);
+ if (rc) {
+ reason = "tpm2_init_session";
+ goto out_flush_session;
+ }
+ }
+
+ rc = TSS_Execute(tssContext,
+ (RESPONSE_PARAMETERS *)&uout,
+ (COMMAND_PARAMETERS *)&uin,
+ NULL,
+ TPM_CC_Unseal,
+ session, app_data->auth, TPMA_SESSION_ENCRYPT,
+ TPM_RH_NULL, NULL, 0);
+ if (rc) {
+ reason = "TPM2_Unseal";
+ out_flush_session:
+ tpm2_flush_handle(tssContext, session);
+ } else {
+ fwrite(uout.outData.t.buffer, 1, uout.outData.t.size, stdout);
+ }
+
+ out_flush_data:
+ tpm2_flush_handle(tssContext, uin.itemHandle);
+ out_free_app_data:
+ TSS_Delete(tssContext);
+ tpm2_delete(app_data);
+
+ err:
+ if (rc) {
+ if (rc == NOT_TPM_ERROR)
+ fprintf(stderr, "%s failed\n", reason);
+ else
+ tpm2_error(rc, reason);
+ rc = 1;
+ }
+ exit(rc);
+}