Dominique Leuenberger 2024-08-08 08:57:03 +00:00 committed by Git OBS Bridge
commit 7c7e9fe35b
4 changed files with 482 additions and 0 deletions

View File

@ -0,0 +1,58 @@
From 61f9b77634578c0bf0c3bf6c4b386057e8661a1c Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Wed, 12 Jun 2024 14:41:38 +0800
Subject: [PATCH] testcase: fix playback on empty EFI variables
For systems in UEFI Setup mode, there is no PK, KEK, or db. However,
those variables are still recorded in the TPM event log with zero
length. To avoid failing on reading those files, this commit changes the
file reading flag so that testcase playback won't stop on those EFI
variables.
Signed-off-by: Gary Lin <glin@suse.com>
---
src/testcase.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/testcase.c b/src/testcase.c
index f74238b..998aedd 100644
--- a/src/testcase.c
+++ b/src/testcase.c
@@ -224,12 +224,18 @@ testcase_write_file(const char *directory, const char *name, const buffer_t *bp)
}
static buffer_t *
-testcase_read_file(const char *directory, const char *name)
+__testcase_read_file(const char *directory, const char *name, int flags)
{
char path[PATH_MAX];
snprintf(path, sizeof(path), "%s/%s", directory, name);
- return runtime_read_file(path, 0);
+ return runtime_read_file(path, flags);
+}
+
+static buffer_t *
+testcase_read_file(const char *directory, const char *name)
+{
+ return __testcase_read_file(directory, name, 0);
}
testcase_t *
@@ -314,7 +320,12 @@ testcase_record_efi_variable(testcase_t *tc, const char *name, const buffer_t *d
buffer_t *
testcase_playback_efi_variable(testcase_t *tc, const char *name)
{
- return testcase_read_file(tc->efi_directory, name);
+ /* For systems in UEFI Setup mode, there is no PK, KEK, or db, but those
+ * variables are still recorded in the TPM event log with zero length.
+ * Set the file reading flag to skip those EFI variable files.
+ */
+ return __testcase_read_file(tc->efi_directory, name,
+ RUNTIME_MISSING_FILE_OKAY);
}
void
--
2.35.3

View File

@ -1,3 +1,10 @@
-------------------------------------------------------------------
Mon Aug 5 06:11:52 UTC 2024 - Gary Ching-Pang Lin <glin@suse.com>
- Add support-ecc-srk.patch to support ECC SRK
- Add fix-testcase-empty-efi-variables.patch to fix the testcase
playback on empty EFI variables
-------------------------------------------------------------------
Mon Mar 25 20:16:53 UTC 2024 - Alberto Planas Dominguez <aplanas@suse.com>

View File

@ -34,6 +34,10 @@ Patch1: fix_loader_conf.patch
Patch2: fix_grub_bls_entry.patch
# PATCH-FIX-UPSTREAM fix_grub_bls_cmdline.patch gh#okirch/pcr-oracle!52 (cont)
Patch3: fix_grub_bls_cmdline.patch
# PATCH-FIX-UPSTREAM support-ecc-srk.patch gh#okirch/pcr-oracle!56
Patch4: support-ecc-srk.patch
# PATCH-FIX-UPSTREAM fix-testcase-empty-efi-variables.patch gh#okirch/pcr-oracle!58
Patch5: fix-testcase-empty-efi-variables.patch
BuildRequires: libopenssl-devel >= 0.9.8
BuildRequires: tpm2-0-tss-devel >= 2.4.0
Requires: libtss2-tcti-device0

413
support-ecc-srk.patch Normal file
View File

@ -0,0 +1,413 @@
From 60ce42dbf61ce89012d9bc71c92c5cc92759b02c Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Wed, 3 Apr 2024 14:41:49 +0800
Subject: [PATCH 1/3] Update the comment for SRK template
USERWITHAUTH and NODA are set according to "TCG TPM v2.0 Provisioning
Guidance". This commit updates the comment to add the reference.
Signed-off-by: Gary Lin <glin@suse.com>
---
src/pcr-policy.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/pcr-policy.c b/src/pcr-policy.c
index 8f2c42c..f03b6e0 100644
--- a/src/pcr-policy.c
+++ b/src/pcr-policy.c
@@ -67,8 +67,9 @@ static TPM2B_PUBLIC SRK_template = {
.publicArea = {
.type = TPM2_ALG_RSA,
.nameAlg = TPM2_ALG_SHA256,
- /* For reasons not clear to me, grub2 derives the SRK using the NODA attribute,
- * which means it is not subject to dictionary attack protections. */
+ /* Per "Storage Primary Key (SRK) Templates" in section 7.5.1 of
+ * TCG TPM v2.0 Provisioning Guidance 1.0 Revision 1.0, the
+ * template for shared SRKs sets USERWITHAUTH and NODA. */
.objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT \
|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT \
|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH \
--
2.35.3
From 0085c5a6a47f433dc69739c54b9db11796aff62e Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Wed, 10 Apr 2024 16:20:44 +0800
Subject: [PATCH 2/3] Support SRK template with ECC_NIST_P256
When sealing data with SRK, the data is actually encrypted with the
symmetric key, and the selection of the asymmetric algorithm is only
a parameter for KDF to derive the symmetric key. Compared with RSA,
ECC NIST-P256 provides the faster key generation, so it's a better
choice for the SRK template in general.
This commit adds a new option, '--ecc-srk', to switch the default SRK
template from the RSA one to the ECC one, so that the user can specify
the SRK template when sealing/unsealing data.
Signed-off-by: Gary Lin <glin@suse.com>
---
src/oracle.c | 7 +++++++
src/pcr-policy.c | 44 +++++++++++++++++++++++++++++++++++++++++---
src/pcr.h | 1 +
3 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/src/oracle.c b/src/oracle.c
index 1cafafc..f391430 100644
--- a/src/oracle.c
+++ b/src/oracle.c
@@ -92,6 +92,7 @@ enum {
OPT_RSA_PUBLIC_KEY,
OPT_RSA_GENERATE_KEY,
OPT_RSA_BITS,
+ OPT_ECC_SRK,
OPT_INPUT,
OPT_OUTPUT,
OPT_AUTHORIZED_POLICY,
@@ -125,6 +126,7 @@ static struct option options[] = {
{ "public-key", required_argument, 0, OPT_RSA_PUBLIC_KEY },
{ "rsa-generate-key", no_argument, 0, OPT_RSA_GENERATE_KEY },
{ "rsa-bits", required_argument, 0, OPT_RSA_BITS },
+ { "ecc-srk", no_argument, 0, OPT_ECC_SRK },
{ "input", required_argument, 0, OPT_INPUT },
{ "output", required_argument, 0, OPT_OUTPUT },
{ "authorized-policy", required_argument, 0, OPT_AUTHORIZED_POLICY },
@@ -1042,6 +1044,8 @@ main(int argc, char **argv)
unsigned int rsa_bits = 2048;
int c, exit_code = 0;
+ set_srk_alg("RSA");
+
while ((c = getopt_long(argc, argv, "dhA:CF:LSZ", options, NULL)) != EOF) {
switch (c) {
case 'A':
@@ -1109,6 +1113,9 @@ main(int argc, char **argv)
case OPT_RSA_BITS:
opt_rsa_bits = optarg;
break;
+ case OPT_ECC_SRK:
+ set_srk_alg("ECC");
+ break;
case OPT_INPUT:
opt_input = optarg;
break;
diff --git a/src/pcr-policy.c b/src/pcr-policy.c
index f03b6e0..f65becf 100644
--- a/src/pcr-policy.c
+++ b/src/pcr-policy.c
@@ -62,7 +62,7 @@ struct target_platform {
const stored_key_t *public_key_file);
};
-static TPM2B_PUBLIC SRK_template = {
+static TPM2B_PUBLIC RSA_SRK_template = {
.size = sizeof(TPMT_PUBLIC),
.publicArea = {
.type = TPM2_ALG_RSA,
@@ -88,6 +88,35 @@ static TPM2B_PUBLIC SRK_template = {
}
};
+static TPM2B_PUBLIC ECC_SRK_template = {
+ .size = sizeof(TPMT_PUBLIC),
+ .publicArea = {
+ .type = TPM2_ALG_ECC,
+ .nameAlg = TPM2_ALG_SHA256,
+ /* Per "Storage Primary Key (SRK) Templates" in section 7.5.1 of
+ * TCG TPM v2.0 Provisioning Guidance 1.0 Revision 1.0, the
+ * template for shared SRKs sets USERWITHAUTH and NODA. */
+ .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT \
+ |TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT \
+ |TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH \
+ |TPMA_OBJECT_NODA,
+ .parameters = {
+ .eccDetail = {
+ .symmetric = {
+ .algorithm = TPM2_ALG_AES,
+ .keyBits = { .sym = 128 },
+ .mode = { .sym = TPM2_ALG_CFB },
+ },
+ .scheme = { TPM2_ALG_NULL },
+ .curveID = TPM2_ECC_NIST_P256,
+ .kdf.scheme = TPM2_ALG_NULL
+ }
+ }
+ }
+};
+
+static const TPM2B_PUBLIC *SRK_template;
+
static const TPM2B_PUBLIC seal_public_template = {
.size = sizeof(TPMT_PUBLIC),
.publicArea = {
@@ -107,10 +136,19 @@ static const TPM2B_PUBLIC seal_public_template = {
}
};
+void
+set_srk_alg (const char *alg)
+{
+ if (strcmp(alg, "RSA") == 0)
+ SRK_template = &RSA_SRK_template;
+ else
+ SRK_template = &ECC_SRK_template;
+}
+
void
set_srk_rsa_bits (const unsigned int rsa_bits)
{
- SRK_template.publicArea.parameters.rsaDetail.keyBits = rsa_bits;
+ RSA_SRK_template.publicArea.parameters.rsaDetail.keyBits = rsa_bits;
}
static inline const tpm_evdigest_t *
@@ -609,7 +647,7 @@ esys_create_primary(ESYS_CONTEXT *esys_context, ESYS_TR *handle_ret)
t0 = timing_begin();
rc = Esys_CreatePrimary(esys_context, ESYS_TR_RH_OWNER,
ESYS_TR_PASSWORD,
- ESYS_TR_NONE, ESYS_TR_NONE, &in_sensitive, &SRK_template,
+ ESYS_TR_NONE, ESYS_TR_NONE, &in_sensitive, SRK_template,
NULL, &creation_pcr, handle_ret,
NULL, NULL,
NULL, NULL);
diff --git a/src/pcr.h b/src/pcr.h
index 4d8f816..f1dc9af 100644
--- a/src/pcr.h
+++ b/src/pcr.h
@@ -39,6 +39,7 @@ typedef struct tpm_pcr_selection {
const tpm_algo_info_t * algo_info;
} tpm_pcr_selection_t;
+extern void set_srk_alg (const char *alg);
extern void set_srk_rsa_bits (const unsigned int rsa_bits);
extern void pcr_bank_initialize(tpm_pcr_bank_t *bank, unsigned int pcr_mask, const tpm_algo_info_t *algo);
extern bool pcr_bank_wants_pcr(tpm_pcr_bank_t *bank, unsigned int index);
--
2.35.3
From 207bd496868d65455e63aa9586bfc6e02900a4a1 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Wed, 24 Apr 2024 14:53:25 +0800
Subject: [PATCH 3/3] Update to conform the latest TPM 2.0 Key File
For TPM 2.0 Key File, the default asymmetric algorithm of SRK is ECC
NIST-P256, not RSA 2048. A new field 'rsaParent' is introduced to note
the key is sealed with RSA SRK.
This commit implements two new fields: description and rsaParent in
tpm2key.c/tpm2key-asn.h and sets rsaParent when RSA SRK is used to seal
the key. When unsealing a tpm2key, the SRK template is set to the RSA
template if rsaParent is TRUE. Otherwise, the SRK template is switched
to the ECC SRK template.
A new testing script, test-tpm2key-ecc.sh, is also added to test the
tpm2key file sealed with ECC SRK.
Signed-off-by: Gary Lin <glin@suse.com>
---
src/pcr-policy.c | 8 +++
src/tpm2key-asn.h | 4 ++
src/tpm2key.c | 2 +
test-tpm2key-ecc.sh | 127 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 141 insertions(+)
create mode 100755 test-tpm2key-ecc.sh
diff --git a/src/pcr-policy.c b/src/pcr-policy.c
index f65becf..90f60ff 100644
--- a/src/pcr-policy.c
+++ b/src/pcr-policy.c
@@ -1505,6 +1505,11 @@ tpm2key_unseal_secret(const char *input_path, const char *output_path,
if (!tpm2key_read_file(input_path, &tpm2key))
return false;
+ if (tpm2key->rsaParent == 1)
+ SRK_template = &RSA_SRK_template;
+ else
+ SRK_template = &ECC_SRK_template;
+
buffer_init_read(&buf, tpm2key->pubkey->data, tpm2key->pubkey->length);
rc = Tss2_MU_TPM2B_PUBLIC_Unmarshal(buf.data, buf.size, &buf.rpos, &pub);
if (rc != TSS2_RC_SUCCESS)
@@ -1634,6 +1639,9 @@ tpm2key_write_sealed_secret(const char *pathname,
if (!tpm2key_basekey(&tpm2key, TPM2_RH_OWNER, sealed_public, sealed_private))
goto cleanup;
+ if (SRK_template->publicArea.type == TPM2_ALG_RSA)
+ tpm2key->rsaParent = 1;
+
if (pcr_sel && !tpm2key_add_policy_policypcr(tpm2key, pcr_sel))
goto cleanup;
diff --git a/src/tpm2key-asn.h b/src/tpm2key-asn.h
index 3f1c0d7..d0cdfaa 100644
--- a/src/tpm2key-asn.h
+++ b/src/tpm2key-asn.h
@@ -77,6 +77,8 @@ DEFINE_STACK_OF(TSSAUTHPOLICY);
* policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL
* secret [2] EXPLICIT OCTET STRING OPTIONAL
* authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL
+ * description [4] EXPLICIT UTF8String OPTIONAL
+ * rsaParent [5] EXPLICIT BOOLEAN OPTIONAL
* parent INTEGER
* pubkey OCTET STRING
* privkey OCTET STRING
@@ -89,6 +91,8 @@ typedef struct {
STACK_OF(TSSOPTPOLICY) *policy;
ASN1_OCTET_STRING *secret;
STACK_OF(TSSAUTHPOLICY) *authPolicy;
+ ASN1_UTF8STRING description;
+ ASN1_BOOLEAN rsaParent;
ASN1_INTEGER *parent;
ASN1_OCTET_STRING *pubkey;
ASN1_OCTET_STRING *privkey;
diff --git a/src/tpm2key.c b/src/tpm2key.c
index cabd791..af4c984 100644
--- a/src/tpm2key.c
+++ b/src/tpm2key.c
@@ -278,6 +278,8 @@ ASN1_SEQUENCE(TSSPRIVKEY) = {
ASN1_EXP_SEQUENCE_OF_OPT(TSSPRIVKEY, policy, TSSOPTPOLICY, 1),
ASN1_EXP_OPT(TSSPRIVKEY, secret, ASN1_OCTET_STRING, 2),
ASN1_EXP_SEQUENCE_OF_OPT(TSSPRIVKEY, authPolicy, TSSAUTHPOLICY, 3),
+ ASN1_EXP_OPT(TSSPRIVKEY, description, ASN1_UTF8STRING, 4),
+ ASN1_EXP_OPT(TSSPRIVKEY, rsaParent, ASN1_BOOLEAN, 5),
ASN1_SIMPLE(TSSPRIVKEY, parent, ASN1_INTEGER),
ASN1_SIMPLE(TSSPRIVKEY, pubkey, ASN1_OCTET_STRING),
ASN1_SIMPLE(TSSPRIVKEY, privkey, ASN1_OCTET_STRING)
diff --git a/test-tpm2key-ecc.sh b/test-tpm2key-ecc.sh
new file mode 100755
index 0000000..d87acff
--- /dev/null
+++ b/test-tpm2key-ecc.sh
@@ -0,0 +1,127 @@
+#!/bin/bash
+#
+# This script needs to be run with root privilege
+#
+
+# TESTDIR=policy.test
+PCR_MASK=0,2,4,12
+
+pcr_oracle=pcr-oracle
+if [ -x pcr-oracle ]; then
+ pcr_oracle=$PWD/pcr-oracle
+fi
+
+function call_oracle {
+
+ echo "****************"
+ echo "pcr-oracle $*"
+ $pcr_oracle --target-platform tpm2.0 -d "$@"
+}
+
+if [ -z "$TESTDIR" ]; then
+ tmpdir=$(mktemp -d /tmp/pcrtestXXXXXX)
+ trap "cd / && rm -rf $tmpdir" 0 1 2 10 11 15
+
+ TESTDIR=$tmpdir
+fi
+
+trap "echo 'FAIL: command exited with error'; exit 1" ERR
+
+echo "This is super secret" >$TESTDIR/secret
+
+set -e
+cd $TESTDIR
+
+echo "Seal the secret with PCR policy"
+call_oracle \
+ --from current \
+ --input secret \
+ --output sealed \
+ --ecc-srk \
+ seal-secret $PCR_MASK
+
+echo "Unseal the sealed with PCR policy"
+call_oracle \
+ --input sealed \
+ --output recovered \
+ unseal-secret
+
+if ! cmp secret recovered; then
+ echo "BAD: Unable to recover original secret"
+ echo "Secret:"
+ od -tx1c secret
+ echo "Recovered:"
+ od -tx1c recovered
+ exit 1
+else
+ echo "NICE: we were able to recover the original secret"
+fi
+
+rm -f sealed recovered
+
+call_oracle \
+ --rsa-generate-key \
+ --private-key policy-key.pem \
+ --auth authorized.policy \
+ create-authorized-policy $PCR_MASK
+
+call_oracle \
+ --private-key policy-key.pem \
+ --public-key policy-pubkey \
+ store-public-key
+
+call_oracle \
+ --auth authorized.policy \
+ --input secret \
+ --output sealed \
+ --ecc-srk \
+ seal-secret
+
+for attempt in first second; do
+ echo "Sign the set of PCRs we want to authorize"
+ call_oracle \
+ --policy-name "authorized-policy-test" \
+ --private-key policy-key.pem \
+ --from current \
+ --input sealed \
+ --output sealed-signed \
+ sign $PCR_MASK
+
+ echo "$attempt attempt to unseal the secret"
+ call_oracle \
+ --input sealed-signed \
+ --output recovered \
+ unseal-secret
+
+ if ! cmp secret recovered; then
+ echo "BAD: Unable to recover original secret"
+ echo "Secret:"
+ od -tx1c secret
+ echo "Recovered:"
+ od -tx1c recovered
+ exit 1
+ else
+ echo "NICE: we were able to recover the original secret"
+ fi
+
+ if [ "$attempt" = "second" ]; then
+ break
+ fi
+
+ echo "Extend PCR 12. Unsealing should fail afterwards"
+ tpm2_pcrextend 12:sha256=21d2013e3081f1e455fdd5ba6230a8620c3cfc9a9c31981d857fe3891f79449e
+ rm -f recovered
+ call_oracle \
+ --input sealed-signed \
+ --output recovered \
+ unseal-secret || true
+
+ if [ -s recovered ] && ! cmp secret recovered; then
+ echo "BAD: We were still able to recover the original secret. Something stinks"
+ exit 1
+ else
+ echo "GOOD: After changing a PCR, the secret can no longer be unsealed"
+ fi
+
+ echo "Now recreate the signed PCR policy"
+done
--
2.35.3