File TEST-persistent-srk.patch of Package pcr-oracle
diff --git a/src/oracle.c b/src/oracle.c
index 4496b4d..09601a3 100644
--- a/src/oracle.c
+++ b/src/oracle.c
@@ -104,6 +104,7 @@ enum {
OPT_TARGET_PLATFORM,
OPT_BOOT_ENTRY,
OPT_COMPARE_CURRENT,
+ OPT_PERSISTENT_SRK,
};
static struct option options[] = {
@@ -139,6 +140,7 @@ static struct option options[] = {
{ "target-platform", required_argument, 0, OPT_TARGET_PLATFORM },
{ "next-kernel", required_argument, 0, OPT_BOOT_ENTRY },
{ "compare-current", no_argument, 0, OPT_COMPARE_CURRENT },
+ { "persistent-srk", required_argument, 0, OPT_PERSISTENT_SRK },
{ NULL }
};
@@ -1175,6 +1177,7 @@ main(int argc, char **argv)
char *opt_target_platform = NULL;
char *opt_boot_entry = NULL;
bool opt_compare_current = false;
+ char *opt_persistent_srk = NULL;
const target_platform_t *target;
unsigned int action_flags = 0;
unsigned int rsa_bits = 2048;
@@ -1281,6 +1284,9 @@ main(int argc, char **argv)
case OPT_COMPARE_CURRENT:
opt_compare_current = true;
break;
+ case OPT_PERSISTENT_SRK:
+ opt_persistent_srk = optarg;
+ break;
case 'h':
usage(0, NULL);
default:
@@ -1443,7 +1449,7 @@ main(int argc, char **argv)
/* When sealing a secret against an authorized policy, there's no need to
* mess around with PCR values. That's the beauty of it... */
if (action == ACTION_SEAL && opt_authorized_policy) {
- if (!pcr_authorized_policy_seal_secret(target, opt_authorized_policy, opt_input, opt_output))
+ if (!pcr_authorized_policy_seal_secret(target, opt_authorized_policy, opt_persistent_srk, opt_input, opt_output))
return 1;
return 0;
@@ -1491,7 +1497,7 @@ main(int argc, char **argv)
predictor_report(pred);
} else
if (action == ACTION_SEAL) {
- if (!pcr_seal_secret(target, &pred->prediction, opt_input, opt_output))
+ if (!pcr_seal_secret(target, &pred->prediction, opt_persistent_srk, opt_input, opt_output))
return 1;
} else
if (action == ACTION_SIGN) {
diff --git a/src/pcr-policy.c b/src/pcr-policy.c
index 3c08775..9183d8a 100644
--- a/src/pcr-policy.c
+++ b/src/pcr-policy.c
@@ -47,6 +47,7 @@ struct target_platform {
unsigned int unseal_flags;
bool (*write_sealed_secret)(const char *pathname,
+ const TPM2_HANDLE persistent_addr,
const TPML_PCR_SELECTION *pcr_sel,
const TPM2B_PRIVATE *sealed_private,
const TPM2B_PUBLIC *sealed_public);
@@ -659,6 +660,69 @@ esys_create_primary(ESYS_CONTEXT *esys_context, ESYS_TR *handle_ret)
return true;
}
+static bool
+esys_make_handle_persistent(ESYS_CONTEXT *esys_context, ESYS_TR handle, TPMI_DH_PERSISTENT persistent_handle, ESYS_TR *obj_handle)
+{
+ ESYS_TR tmp_obj;
+ TSS2_RC rc;
+
+ if (obj_handle == NULL)
+ return false;
+
+ /* Try to make the object persistent */
+ infomsg("Making SRK persistent in 0x%X\n", persistent_handle);
+ rc = Esys_EvictControl(esys_context,
+ ESYS_TR_RH_OWNER, /* auth */
+ handle, /* objectHandle */
+ ESYS_TR_PASSWORD, /* shandle1 */
+ ESYS_TR_NONE, /* shandle2 */
+ ESYS_TR_NONE, /* shandle3 */
+ persistent_handle, /* persistentHandle */
+ obj_handle /* newObjectHandle */
+ );
+
+ /* If a persistent object already exists in the persistent handle (address),
+ * TPM2_EvictControl returns TPM2_RC_NV_DEFINED. */
+ if (rc == TSS2_RC_SUCCESS)
+ return true;
+ else if (rc != TPM2_RC_NV_DEFINED && !tss_check_error(rc, "Esys_EvictControl failed"))
+ return false;
+
+ /* Remove the object from the specified persistent handle (address) */
+ infomsg("Removing the previous persistent object from 0x%X\n", persistent_handle);
+ rc = Esys_TR_FromTPMPublic(esys_context, persistent_handle,
+ ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &tmp_obj);
+ if (!tss_check_error(rc, "Esys_TR_FromTPMPublic failed"))
+ return false;
+ rc = Esys_EvictControl(esys_context,
+ ESYS_TR_RH_OWNER, /* auth */
+ tmp_obj, /* objectHandle */
+ ESYS_TR_PASSWORD, /* shandle1 */
+ ESYS_TR_NONE, /* shandle2 */
+ ESYS_TR_NONE, /* shandle3 */
+ persistent_handle, /* persistentHandle */
+ &tmp_obj /* newObjectHandle */
+ );
+ if (!tss_check_error(rc, "Esys_EvictControl failed"))
+ return false;
+
+ /* Try again to make the object persistent */
+ infomsg("Making SRK persistent in 0x%X again\n", persistent_handle);
+ rc = Esys_EvictControl(esys_context,
+ ESYS_TR_RH_OWNER, /* auth */
+ handle, /* objectHandle */
+ ESYS_TR_PASSWORD, /* shandle1 */
+ ESYS_TR_NONE, /* shandle2 */
+ ESYS_TR_NONE, /* shandle3 */
+ persistent_handle, /* persistentHandle */
+ obj_handle /* newObjectHandle */
+ );
+ if (!tss_check_error(rc, "Esys_EvictControl failed"))
+ return false;
+
+ return true;
+}
+
static bool
esys_create(ESYS_CONTEXT *esys_context,
ESYS_TR srk_handle, TPM2B_DIGEST *authorized_policy, TPM2B_SENSITIVE_DATA *secret,
@@ -690,12 +754,14 @@ esys_create(ESYS_CONTEXT *esys_context,
static bool
esys_seal_secret(const target_platform_t *platform, ESYS_CONTEXT *esys_context,
TPM2B_DIGEST *policy, const TPML_PCR_SELECTION *pcr_sel,
- const char *input_path, const char *output_path)
+ const char *opt_persistent_srk, const char *input_path, const char *output_path)
{
TPM2B_SENSITIVE_DATA *secret = NULL;
TPM2B_PRIVATE *sealed_private = NULL;
TPM2B_PUBLIC *sealed_public = NULL;
ESYS_TR srk_handle = ESYS_TR_NONE;
+ ESYS_TR obj_handle = ESYS_TR_NONE;
+ TPM2_HANDLE persistent_handle = 0;
bool ok = false;
if (!(secret = read_secret(input_path)))
@@ -706,10 +772,24 @@ esys_seal_secret(const target_platform_t *platform, ESYS_CONTEXT *esys_context,
if (!esys_create_primary(esys_context, &srk_handle))
goto cleanup;
+ /* Make SRK persistent if requested */
+ if (opt_persistent_srk != NULL) {
+ /* Convert opt_persistent_srk to TPM2 handle */
+ persistent_handle = strtoul(opt_persistent_srk, NULL, 16);
+ if ((persistent_handle >> TPM2_HR_SHIFT) != TPM2_HT_PERSISTENT) {
+ error("Not a valid persistent handle, e.g. 0x81000000\n");
+ goto cleanup;
+ }
+
+ if (!esys_make_handle_persistent(esys_context, srk_handle,
+ persistent_handle, &obj_handle))
+ goto cleanup;
+ }
+
if (!esys_create(esys_context, srk_handle, policy, secret, &sealed_private, &sealed_public))
goto cleanup;
- ok = platform->write_sealed_secret(output_path, pcr_sel, sealed_private, sealed_public);
+ ok = platform->write_sealed_secret(output_path, persistent_handle, pcr_sel, sealed_private, sealed_public);
if (ok)
infomsg("Sealed secret written to %s\n", output_path?: "(standard output)");
@@ -1052,7 +1132,7 @@ pcr_store_public_key(const stored_key_t *private_key_file, const stored_key_t *p
bool
pcr_seal_secret(const target_platform_t *platform, const tpm_pcr_bank_t *bank,
- const char *input_path, const char *output_path)
+ const char *opt_persistent_srk, const char *input_path, const char *output_path)
{
ESYS_CONTEXT *esys_context = tss_esys_context();
TPM2B_DIGEST *pcr_policy = NULL;
@@ -1066,7 +1146,7 @@ pcr_seal_secret(const target_platform_t *platform, const tpm_pcr_bank_t *bank,
return false;
ok = esys_seal_secret(platform, esys_context, pcr_policy, &pcr_sel,
- input_path, output_path);
+ opt_persistent_srk, input_path, output_path);
free(pcr_policy);
return ok;
@@ -1127,7 +1207,8 @@ pcr_authorized_policy_create(const tpm_pcr_selection_t *pcr_selection, const sto
bool
pcr_authorized_policy_seal_secret(const target_platform_t *platform, const char *authpolicy_path,
- const char *input_path, const char *output_path)
+ const char *opt_persistent_srk, const char *input_path,
+ const char *output_path)
{
ESYS_CONTEXT *esys_context = tss_esys_context();
TPM2B_DIGEST *authorized_policy = NULL;
@@ -1137,7 +1218,7 @@ pcr_authorized_policy_seal_secret(const target_platform_t *platform, const char
return false;
ok = esys_seal_secret(platform, esys_context, authorized_policy, NULL,
- input_path, output_path);
+ opt_persistent_srk, input_path, output_path);
free(authorized_policy);
return ok;
}
@@ -1450,6 +1531,7 @@ tpm2key_unseal_secret(const char *input_path, const char *output_path,
buffer_t buf;
TPM2B_PUBLIC pub = { 0 };
TPM2B_PRIVATE priv = { 0 };
+ TPM2_HANDLE tmp_handle;
ESYS_TR primary_handle = ESYS_TR_NONE;
ESYS_TR sealed_object_handle = ESYS_TR_NONE;
TPM2B_SENSITIVE_DATA *unsealed = NULL;
@@ -1474,7 +1556,14 @@ tpm2key_unseal_secret(const char *input_path, const char *output_path,
if (rc != TSS2_RC_SUCCESS)
goto cleanup;
- if (!esys_create_primary(esys_context, &primary_handle))
+ tmp_handle = ASN1_INTEGER_get(tpm2key->parent);
+ if ((tmp_handle >> TPM2_HR_SHIFT) == TPM2_HT_PERSISTENT) {
+ rc = Esys_TR_FromTPMPublic(esys_context, tmp_handle,
+ ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
+ &primary_handle);
+ if (!tss_check_error(rc, "Esys_TR_FromTPMPublic failed"))
+ goto cleanup;
+ } else if (!esys_create_primary(esys_context, &primary_handle))
goto cleanup;
rc = Esys_Load(esys_context, primary_handle,
@@ -1543,6 +1632,7 @@ pcr_unseal_secret(const target_platform_t *platform,
*/
static bool
oldgrub_write_sealed_secret(const char *pathname,
+ const TPM2_HANDLE persistent_addr,
const TPML_PCR_SELECTION *pcr_sel,
const TPM2B_PRIVATE *sealed_private,
const TPM2B_PUBLIC *sealed_public)
@@ -1583,14 +1673,21 @@ oldgrub_unseal_secret(const char *input_path, const char *output_path,
*/
static bool
tpm2key_write_sealed_secret(const char *pathname,
+ const TPM2_HANDLE persistent_addr,
const TPML_PCR_SELECTION *pcr_sel,
const TPM2B_PRIVATE *sealed_private,
const TPM2B_PUBLIC *sealed_public)
{
TSSPRIVKEY *tpm2key = NULL;
+ TPM2_HANDLE parent;
bool ok = false;
- if (!tpm2key_basekey(&tpm2key, TPM2_RH_OWNER, sealed_public, sealed_private))
+ if (persistent_addr == 0)
+ parent = TPM2_RH_OWNER;
+ else
+ parent = persistent_addr;
+
+ if (!tpm2key_basekey(&tpm2key, parent, sealed_public, sealed_private))
goto cleanup;
if (SRK_template->publicArea.type == TPM2_ALG_RSA)
diff --git a/src/pcr.h b/src/pcr.h
index f1dc9af..50fb0ec 100644
--- a/src/pcr.h
+++ b/src/pcr.h
@@ -67,10 +67,11 @@ extern bool pcr_policy_sign(const target_platform_t *platform, const tpm_pcr_ba
const char *input_path,
const char *output_path, const char *policy_name);
extern bool pcr_authorized_policy_seal_secret(const target_platform_t *platform,
- const char *authorized_policy, const char *input_path,
- const char *output_path);
-extern bool pcr_seal_secret(const target_platform_t *, const tpm_pcr_bank_t *bank,
+ const char *opt_persistent_srk, const char *authorized_policy,
const char *input_path, const char *output_path);
+extern bool pcr_seal_secret(const target_platform_t *, const tpm_pcr_bank_t *bank,
+ const char *opt_persistent_srk, const char *input_path,
+ const char *output_path);
extern bool pcr_unseal_secret(const target_platform_t *,
const tpm_pcr_selection_t *pcr_selection,
const char *signed_policy_path,
diff --git a/src/tpm2key.c b/src/tpm2key.c
index af4c984..66ff330 100644
--- a/src/tpm2key.c
+++ b/src/tpm2key.c
@@ -53,7 +53,8 @@ tpm2key_basekey(TSSPRIVKEY **tpm2key, const TPM2_HANDLE parent,
key->type = OBJ_txt2obj(OID_sealedData, 1);
key->emptyAuth = 1;
key->parent = ASN1_INTEGER_new();
- ASN1_INTEGER_set(key->parent, parent);
+ /* Convert 'parent' to 'int32_t' to make sure 'parent' only occupies 4 bytes */
+ ASN1_INTEGER_set(key->parent, (int32_t)parent);
key->pubkey = ASN1_OCTET_STRING_new();
ASN1_STRING_set(key->pubkey, bp_pub->data, buffer_available(bp_pub));