Skip to content

Commit

Permalink
TPM sealing cleanups. If using simulator don't extend the unseal PCR …
Browse files Browse the repository at this point in the history
…to prevent further access. Added `WOLFBOOT_NO_UNSEAL_PCR_EXTEND` option to prevent locking of PCR by random extend. Improvements to the `policy_sign` tool (example usage, ecc384 support).
  • Loading branch information
dgarske committed Oct 6, 2023
1 parent 389e12f commit eb2978a
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 59 deletions.
29 changes: 27 additions & 2 deletions docs/TPM.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ NOTE: The TPM's RSA verify requires ASN.1 encoding, so use SIGN=RSA2048ENC
% ./tools/tpm/pcr_extend 0 aaa.bin
% ./tools/tpm/policy_create -pcr=0
# if ROT enabled
% ./tools/tpm/rot -write
% ./tools/tpm/rot -write [-auth=TestAuth]
% make clean && make POLICY_FILE=policy.bin
% ./wolfboot.elf get_version
Expand Down Expand Up @@ -168,7 +168,31 @@ Building firmware with the policy digest to sign:
% make POLICY_FILE=policy.bin
```
OR manually using:
OR manually sign the policy using the `tools/tpm/policy_sign` or `tools/keytools/sign` tools.
These tools do not need access to a TPM, they are signing a policy digest. The result is a 32-bit PCR mask + signature.
Sign with policy_sign tool:
```sh
% ./tools/tpm/policy_sign -pcr=0 -pcrdigest=eca4e8eda468b8667244ae972b8240d3244ea72341b2bf2383e79c66643bbecc
Sign PCR Policy Tool
Signing Algorithm: ECC256
PCR Index(s) (SHA256): 0
Policy Signing Key: wolfboot_signing_private_key.der
PCR Digest (32 bytes):
eca4e8eda468b8667244ae972b8240d3244ea72341b2bf2383e79c66643bbecc
PCR Policy Digest (32 bytes):
2d401eb05f45ba2b15c35f628b5896cc7de9745bb6e722363e2dbee804e0500f
PCR Policy Digest (w/PolicyRef) (32 bytes):
749b3139ece21449a7828f11ee05303b0473ff1a26cf41d6f9ff28b24c717f02
PCR Mask (0x1) and Policy Signature (68 bytes):
01000000
5b5f875b3f7ce78b5935abe4fc5a4d8a6e87c4b4ac0836fbab909e232b6d7ca2
3ecfc6be723b695b951ba2886d3c7b83ab2f8cc0e96d766bc84276eaf3f213ee
Wrote PCR Mask + Signature (68 bytes) to policy.bin.sig
```
Sign using the signing key tool:
```sh
% ./tools/keytools/sign --ecc256 --policy policy.bin test-app/image.elf wolfboot_signing_private_key.der 1
Expand All @@ -186,5 +210,6 @@ Calculating SHA256 digest...
Signing the digest...
Opening policy file policy.bin
Signing the policy digest...
Saving policy signature to policy.bin.sig
Output image(s) successfully created.
```
8 changes: 8 additions & 0 deletions src/tpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,10 @@ int wolfBoot_seal_blob(const uint8_t* pubkey_hint, const uint8_t* policy, uint16
/* get public key for policy authorization */
rc = wolfBoot_load_pubkey(pubkey_hint, &authKey, &alg);

#ifdef WOLFBOOT_DEBUG_TPM
wolfBoot_printf("Seal: Pub Key %d\n", alg);
#endif

/* The handle for the public key if not needed, so unload it.
* For seal only a populated TPM2B_PUBLIC is required */
wolfTPM2_UnloadHandle(&wolftpm_dev, &authKey.handle);
Expand Down Expand Up @@ -885,6 +889,10 @@ int wolfBoot_unseal_blob(const uint8_t* pubkey_hint,
memset(pcrArray, 0, sizeof(pcrArray));
pcrArraySz = wolfBoot_tpm_pcrmask_sel(pcrMask, pcrArray, sizeof(pcrArray));

#ifdef WOLFBOOT_DEBUG_TPM
wolfBoot_printf("Unseal: PCR mask 0x%x (sz %d)\n", pcrMask, pcrArraySz);
#endif

/* skip to signature */
policy += sizeof(pcrMask);
policySz -= sizeof(pcrMask);
Expand Down
5 changes: 3 additions & 2 deletions src/update_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,7 @@ int wolfBoot_unlock_disk(void)


/* Extend a PCR from the mask to prevent future unsealing */
#if !defined(ARCH_SIM) && !defined(WOLFBOOT_NO_UNSEAL_PCR_EXTEND)
{
uint32_t pcrMask;
uint32_t pcrArraySz;
Expand All @@ -670,8 +671,8 @@ int wolfBoot_unlock_disk(void)
pcrArraySz = wolfBoot_tpm_pcrmask_sel(pcrMask,
pcrArray, sizeof(pcrArray)); /* get first PCR from mask */
wolfBoot_tpm2_extend(pcrArray[0], (uint8_t*)digest, __LINE__);
}

}
#endif
}
else {
wolfBoot_printf("unlock disk failed! %d (%s)\n",
Expand Down
120 changes: 65 additions & 55 deletions tools/tpm/policy_sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,31 @@
*/


#include "wolfssl/wolfcrypt/types.h"
#include <wolftpm/tpm2.h>
#include <wolftpm/tpm2_wrap.h>

#include <stdio.h>

#include <hal/tpm_io.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/hash.h>
#include <wolftpm/tpm2_wrap.h>
#include "tpm.h"

/* Default PCR (test) */
#define DEFAULT_PCR 16

/* Prefer SHA2-256 for PCR's, and all TPM 2.0 devices support it */
#define USE_PCR_ALG TPM_ALG_SHA256
enum sign_alg {
ECC256 = 0,
};

static void usage(void)
{
printf("Expected usage:\n");
printf("./examples/pcr/policy_sign [-ecc256] [-key=pem/der] [-pcr] [-pcrdisgest] [-outpolicy=] policy_file\n");
printf("* -ecc256: Use ECC256P1 key\n");
printf("* -key=keyfile: Private key to sign PCR policy (PEM or DER)\n");
printf("* -pcr=index: PCR index < 24 (multiple can be supplied) (default 0)\n");
printf("./examples/pcr/policy_sign [-ecc256/-ecc384] [-key=pem/der] [-pcr=] [-pcrdigest=] [-policydigest=][-outpolicy=]\n");
printf("* -ecc256/-ecc384: Key type (currently only ECC) (default SECP256R1)\n");
printf("* -key=keyfile: Private key to sign PCR policy (PEM or DER) (default wolfboot_signing_private_key.der)\n");
printf("* -pcr=index: PCR index < 24 (multiple can be supplied) (default %d)\n", DEFAULT_PCR);
printf("* -pcrdigest=hexstr: PCR Digest (default=Read actual PCR's)\n");
printf("* -out=file: Signature file (default policy.bin.sig)\n");
printf("* -policydigest=hexstr: Policy Digest (policy based on PCR digest and PCR(s)\n");
printf("* -outpolicy=file: Signature file (default policy.bin.sig)\n");
printf("Example:\n");
printf("\t./tools/tpm/policy_sign -ecc256 -pcr=0 -pcrdigest=eca4e8eda468b8667244ae972b8240d3244ea72341b2bf2383e79c66643bbecc\n");
}


Expand Down Expand Up @@ -98,8 +99,8 @@ static int loadFile(const char* fname, byte** buf, size_t* bufLen)
}

/* Function to sign policy with external key */
static int PolicySign(enum sign_alg alg, const char* keyFile, byte* hash,
word32 hashSz, byte* sig, word32* sigSz)
static int PolicySign(int alg, const char* keyFile, byte* hash, word32 hashSz,
byte* sig, word32* sigSz)
{
int rc = 0;
byte* buf = NULL;
Expand All @@ -114,8 +115,8 @@ static int PolicySign(enum sign_alg alg, const char* keyFile, byte* hash,
#endif
} key;

XMEMSET(&key, 0, sizeof(key));
XMEMSET(&rng, 0, sizeof(rng));
memset(&key, 0, sizeof(key));
memset(&rng, 0, sizeof(rng));

rc = wc_InitRng(&rng);
if (rc != 0) {
Expand All @@ -124,20 +125,21 @@ static int PolicySign(enum sign_alg alg, const char* keyFile, byte* hash,
}

rc = loadFile(keyFile, &buf, &bufSz);
if (rc == 0 && alg == ECC256) {
if (rc == 0 && (alg == ECC_SECP256R1 || alg == ECC_SECP384R1)) {
word32 keySz = 32;
if (alg == ECC_SECP384R1)
keySz = 48;
rc = wc_ecc_init(&key.ecc);
if (rc == 0) {
rc = wc_ecc_import_unsigned(&key.ecc, buf,
(buf) + 32, buf + 64,
ECC_SECP256R1);
(buf) + keySz, buf + (keySz*2), alg);
if (rc == 0) {
mp_int r, s;
rc = mp_init_multi(&r, &s, NULL, NULL, NULL, NULL);
if (rc == 0) {
rc = wc_ecc_sign_hash_ex(hash, hashSz, &rng, &key.ecc, &r, &s);
}
if (rc == 0) {
word32 keySz = key.ecc.dp->size;
mp_to_unsigned_bin(&r, sig);
mp_to_unsigned_bin(&s, sig + keySz);
mp_clear(&r);
Expand Down Expand Up @@ -231,10 +233,10 @@ int policy_sign(int argc, char *argv[])
int i;
int rc = -1;
TPM_ALG_ID pcrAlg = USE_PCR_ALG;
enum sign_alg alg;
int alg = ECC_SECP256R1;
byte pcrArray[PCR_SELECT_MAX*2];
word32 pcrArraySz = 0;
const char* keyFile = NULL;
const char* keyFile = "wolfboot_signing_private_key.der";
const char* outPolicyFile = "policy.bin.sig";
byte pcrDigest[WC_MAX_DIGEST_SIZE];
word32 pcrDigestSz = 0;
Expand All @@ -257,7 +259,10 @@ int policy_sign(int argc, char *argv[])
}
while (argc > 1) {
if (XSTRCMP(argv[argc-1], "-ecc256") == 0) {
alg = ECC256;
alg = ECC_SECP256R1;
}
else if (XSTRCMP(argv[argc-1], "-ecc384") == 0) {
alg = ECC_SECP384R1;
}
else if (strncmp(argv[argc-1], "-pcr=", strlen("-pcr=")) == 0) {
const char* pcrStr = argv[argc-1] + strlen("-pcr=");
Expand Down Expand Up @@ -310,7 +315,18 @@ int policy_sign(int argc, char *argv[])
argc--;
}

printf("Sign PCR Policy Example\n");
printf("Sign PCR Policy Tool\n");

if (pcrArraySz == 0) {
pcrArray[pcrArraySz] = DEFAULT_PCR;
pcrArraySz++;
}

printf("Signing Algorithm: %s\n",
(alg == ECC_SECP256R1) ? "ECC256" :
(alg == ECC_SECP384R1) ? "ECC384" :
"Unknown"
);

printf("PCR Index(s) (%s): ", TPM2_GetAlgName(pcrAlg));
for (i = 0; i < (int)pcrArraySz; i++) {
Expand All @@ -327,20 +343,18 @@ int policy_sign(int argc, char *argv[])
printf("Policy Signing Key: %s\n", keyFile);
}

/* PCR Hash - Use provided hash or read PCR's and get hash */
/* PCR Hash - Use provided PCR digest or Policy digest */
if (pcrDigestSz == 0 && digestSz == 0) {
printf("Error: Specificy PCR's or Policy hash!\n");
goto exit;
}

if (pcrDigestSz > 0) {
printf("PCR Digest (%d bytes):\n", pcrDigestSz);
printHexString(pcrDigest, pcrDigestSz, pcrDigestSz);
printf("Error: Must supply either PCR or Policy digest!\n");
usage();
return -1;
}
printf("PCR Digest (%d bytes):\n", pcrDigestSz);
printHexString(pcrDigest, pcrDigestSz, pcrDigestSz);

if (digestSz == 0) {
/* Build PCR Policy to Sign */
XMEMSET(digest, 0, sizeof(digest));
/* If not supplied, build PCR Policy to Sign */
memset(digest, 0, sizeof(digest));
digestSz = TPM2_GetHashDigestSize(pcrAlg);
rc = wolfTPM2_PolicyPCRMake(pcrAlg, pcrArray, pcrArraySz,
pcrDigest, pcrDigestSz, digest, &digestSz);
Expand All @@ -358,28 +372,24 @@ int policy_sign(int argc, char *argv[])
printHexString(digest, digestSz, digestSz);

/* Sign the PCR policy (use private key provided or do externally) */
if (keyFile != NULL) {
rc = PolicySign(alg, keyFile, digest, digestSz, sig, &sigSz);
rc = PolicySign(alg, keyFile, digest, digestSz, sig, &sigSz);
if (rc == 0) {
pcrMask = 0;
for (i = 0; i < (int)pcrArraySz; i++)
pcrMask |= (1 << pcrArray[i]);

memcpy(policy, &pcrMask, sizeof(pcrMask));
memcpy(policy + sizeof(pcrMask), sig, sigSz);
printf("PCR Mask (0x%x) and Policy Signature (%d bytes):\n",
(int)pcrMask, (int)(sigSz + sizeof(pcrMask)));
printHexString(policy, sizeof(pcrMask), 0);
printHexString(policy + sizeof(pcrMask), sigSz, 32);
rc = writeBin(outPolicyFile, policy, sigSz+sizeof(pcrMask));
if (rc == 0) {
pcrMask = 0;
for (i = 0; i < (int)pcrArraySz; i++)
pcrMask |= (1 << pcrArray[i]);

memcpy(policy, &pcrMask, sizeof(pcrMask));
memcpy(policy + sizeof(pcrMask), sig, sigSz);
printf("PCR Mask (0x%x) and Policy Signature (%d bytes):\n", (int)pcrMask,
(int)(sigSz + sizeof(pcrMask)));
printHexString(policy, sigSz+sizeof(pcrMask), 32);
rc = writeBin(outPolicyFile, policy, sigSz+sizeof(pcrMask));
printf("Wrote PCR Mask + Signature (%d bytes) to %s\n",
(int)(sigSz + sizeof(pcrMask)), outPolicyFile);
}
}
else {
/* Print policy hash to sign externally and exit early */
printf("No private key to sign policy!\n");
printf("Externally sign the PCR Policy digest\n");
rc = 0;
goto exit;
}

exit:
if (rc != 0) {
Expand Down

0 comments on commit eb2978a

Please sign in to comment.