diff --git a/.github/workflows/test-tpm.yml b/.github/workflows/test-tpm.yml index c27f66ba5..6111ae41f 100644 --- a/.github/workflows/test-tpm.yml +++ b/.github/workflows/test-tpm.yml @@ -34,7 +34,7 @@ jobs: with: arch: host config-file: ./config/examples/sim-tpm.config - make-args: SIGN=RSA2048 HASH=SHA256 + make-args: SIGN=RSA2048ENC HASH=SHA256 sim_tpm_measured_ecc256: @@ -107,5 +107,5 @@ jobs: with: arch: host config-file: ./config/examples/sim-tpm-seal.config - make-args: SIGN=RSA2048 HASH=SHA256 POLICY_FILE=policy.bin + make-args: SIGN=RSA2048ENC HASH=SHA256 POLICY_FILE=policy.bin authstr: TestAuth diff --git a/config/examples/sim-tpm.config b/config/examples/sim-tpm.config index b00e5a879..95639bf91 100644 --- a/config/examples/sim-tpm.config +++ b/config/examples/sim-tpm.config @@ -1,5 +1,6 @@ ARCH=sim TARGET=sim +# note TPM requires ASN.1 encoding for RSA, so use RSA2048ENC, RSA3072ENC, RSA4096ENC SIGN?=ECC256 HASH?=SHA256 SPI_FLASH=0 diff --git a/docs/TPM.md b/docs/TPM.md index befff1a68..8b794caf9 100644 --- a/docs/TPM.md +++ b/docs/TPM.md @@ -49,29 +49,52 @@ The default NV base can be overridden with `WOLFBOOT_TPM_SEAL_NV_BASE`. ### Testing seal/unseal with simulator ```sh -cp config/examples/sim-tpm-seal.config .config -make keytools -make tpmtools -echo aaa > aaa.bin -./tools/tpm/pcr_extend 0 aaa.bin -./tools/tpm/policy_create -pcr=0 +% cp config/examples/sim-tpm-seal.config .config +% make keytools +% make tpmtools +% echo aaa > aaa.bin +% ./tools/tpm/pcr_extend 0 aaa.bin +% ./tools/tpm/policy_create -pcr=0 # if ROT enabled -./tools/tpm/rot -write -make clean && make POLICY_FILE=policy.bin -./wolfboot.elf get_version -Simulator assigned ./internal_flash.dd to base 0x103797000 +% ./tools/tpm/rot -write +% make clean && make POLICY_FILE=policy.bin + +% ./wolfboot.elf get_version +Simulator assigned ./internal_flash.dd to base 0x103378000 +Mfg IBM (0), Vendor SW TPM, Fw 8217.4131 (0x163636), FIPS 140-2 1, CC-EAL4 0 +Unlocking disk... +Boot partition: 0x1033f8000 +Image size 54400 +Error 395 reading blob from NV index 1400300 (error TPM_RC_HANDLE) +Error 395 unsealing secret! (TPM_RC_HANDLE) +Sealed secret does not exist! +Creating new secret (32 bytes) +430dee45553c4a8b75fbc6bcd0890765c48cab760b24b1aa6b633dc0538e0159 +Wrote 210 bytes to NV index 0x1400300 +Read 210 bytes from NV index 0x1400300 +Secret Check 32 bytes +430dee45553c4a8b75fbc6bcd0890765c48cab760b24b1aa6b633dc0538e0159 +Secret 32 bytes +430dee45553c4a8b75fbc6bcd0890765c48cab760b24b1aa6b633dc0538e0159 +Boot partition: 0x1033f8000 +Image size 54400 +TPM Root of Trust valid (id 0) +Simulator assigned ./internal_flash.dd to base 0x103543000 +1 + +% ./wolfboot.elf get_version +Simulator assigned ./internal_flash.dd to base 0x10c01c000 Mfg IBM (0), Vendor SW TPM, Fw 8217.4131 (0x163636), FIPS 140-2 1, CC-EAL4 0 Unlocking disk... -Boot partition: 0x103817000 +Boot partition: 0x10c09c000 Image size 54400 -Sealing 32 bytes -11c6ac0ec972ae567c541750c6ecccd426f131dad3eeca5e6540d901d9f0c336 -Unsealed 32 bytes -11c6ac0ec972ae567c541750c6ecccd426f131dad3eeca5e6540d901d9f0c336 -Boot partition: 0x103817000 +Read 210 bytes from NV index 0x1400300 +Secret 32 bytes +430dee45553c4a8b75fbc6bcd0890765c48cab760b24b1aa6b633dc0538e0159 +Boot partition: 0x10c09c000 Image size 54400 TPM Root of Trust valid (id 0) -Simulator assigned ./internal_flash.dd to base 0x103962000 +Simulator assigned ./internal_flash.dd to base 0x10c1e7000 1 ``` diff --git a/include/tpm.h b/include/tpm.h index 2bf5fe901..e3ea9a56e 100644 --- a/include/tpm.h +++ b/include/tpm.h @@ -51,6 +51,11 @@ extern WOLFTPM2_KEY wolftpm_srk; int wolfBoot_tpm2_init(void); void wolfBoot_tpm2_deinit(void); +#if defined(WOLFBOOT_TPM_VERIFY) || defined(WOLFBOOT_TPM_SEAL) +int wolfBoot_load_pubkey(struct wolfBoot_image* img, WOLFTPM2_KEY* pubKey, + TPM_ALG_ID* pAlg); +#endif + #ifdef WOLFBOOT_TPM_KEYSTORE int wolfBoot_check_rot(int key_slot, uint8_t* pubkey_hint); #endif @@ -58,12 +63,26 @@ int wolfBoot_check_rot(int key_slot, uint8_t* pubkey_hint); #ifdef WOLFBOOT_TPM_SEAL int wolfBoot_get_random(uint8_t* buf, int sz); int wolfBoot_get_pcr_active(uint8_t pcrAlg, uint32_t* pcrMask, uint8_t pcrMax); -int wolfBoot_build_policy(uint8_t pcrAlg, uint32_t pcrMask, uint8_t* policy, uint32_t* policySz, uint8_t* policyRef, uint32_t policyRefSz); -int wolfBoot_get_policy(struct wolfBoot_image* img, uint8_t** policy, uint16_t* policySz); -int wolfBoot_seal(struct wolfBoot_image* img, int index, const uint8_t* secret, int secret_sz); -int wolfBoot_seal_blob(struct wolfBoot_image* img, WOLFTPM2_KEYBLOB* seal_blob, const uint8_t* secret, int secret_sz); -int wolfBoot_unseal(struct wolfBoot_image* img, int index, uint8_t* secret, int* secret_sz); -int wolfBoot_unseal_blob(struct wolfBoot_image* img, WOLFTPM2_KEYBLOB* seal_blob, uint8_t* secret, int* secret_sz); +int wolfBoot_build_policy(uint8_t pcrAlg, uint32_t pcrMask, + uint8_t* policy, uint32_t* policySz, + uint8_t* policyRef, uint32_t policyRefSz); +int wolfBoot_get_policy(struct wolfBoot_image* img, + uint8_t** policy, uint16_t* policySz); + +int wolfBoot_seal(struct wolfBoot_image* img, int index, + const uint8_t* secret, int secret_sz); +int wolfBoot_seal_blob(struct wolfBoot_image* img, WOLFTPM2_KEYBLOB* seal_blob, + const uint8_t* secret, int secret_sz); +int wolfBoot_unseal(struct wolfBoot_image* img, int index, + uint8_t* secret, int* secret_sz); +int wolfBoot_unseal_blob(struct wolfBoot_image* img, WOLFTPM2_KEYBLOB* seal_blob, + uint8_t* secret, int* secret_sz); + +int wolfBoot_read_blob(uint32_t nvIndex, WOLFTPM2_KEYBLOB* blob, + const uint8_t* auth, uint32_t authSz); +int wolfBoot_store_blob(TPMI_RH_NV_AUTH authHandle, uint32_t nvIndex, + word32 nvAttributes, WOLFTPM2_KEYBLOB* blob, + const uint8_t* auth, uint32_t authSz); #endif #ifdef WOLFBOOT_MEASURED_BOOT diff --git a/options.mk b/options.mk index 3b03b6618..b63f9778a 100644 --- a/options.mk +++ b/options.mk @@ -197,9 +197,14 @@ ifeq ($(SIGN),ED448) endif endif -ifeq ($(SIGN),RSA2048) +ifneq ($(findstring RSA2048,$(SIGN)),) KEYGEN_OPTIONS+=--rsa2048 - SIGN_OPTIONS+=--rsa2048 + ifeq ($(SIGN),RSA2048ENC) + SIGN_OPTIONS+=--rsa2048enc + SIGN:=RSA2048 # helps keystore.c check + else + SIGN_OPTIONS+=--rsa2048 + endif WOLFCRYPT_OBJS+= \ $(RSA_EXTRA_OBJS) \ $(MATH_OBJS) \ @@ -232,9 +237,14 @@ ifeq ($(SIGN),RSA2048) endif endif -ifeq ($(SIGN),RSA3072) +ifneq ($(findstring RSA3072,$(SIGN)),) KEYGEN_OPTIONS+=--rsa3072 - SIGN_OPTIONS+=--rsa3072 + ifeq ($(SIGN),RSA3072ENC) + SIGN_OPTIONS+=--rsa3072enc + SIGN:=RSA3072 # helps keystore.c check + else + SIGN_OPTIONS+=--rsa3072 + endif WOLFCRYPT_OBJS+= \ $(RSA_EXTRA_OBJS) \ $(MATH_OBJS) \ @@ -270,9 +280,15 @@ ifeq ($(SIGN),RSA3072) endif endif -ifeq ($(SIGN),RSA4096) +ifneq ($(findstring RSA4096,$(SIGN)),) + SIGN:=RSA4096 KEYGEN_OPTIONS+=--rsa4096 - SIGN_OPTIONS+=--rsa4096 + ifeq ($(SIGN),RSA4096ENC) + SIGN_OPTIONS+=--rsa4096enc + SIGN:=RSA4096 # helps keystore.c check + else + SIGN_OPTIONS+=--rsa4096 + endif WOLFCRYPT_OBJS+= \ $(RSA_EXTRA_OBJS) \ $(MATH_OBJS) \ diff --git a/src/image.c b/src/image.c index b981a95fd..1c7af1b29 100644 --- a/src/image.c +++ b/src/image.c @@ -43,7 +43,47 @@ /* Globals */ static uint8_t digest[WOLFBOOT_SHA_DIGEST_SIZE]; +/* TPM based verify */ +#if defined(WOLFBOOT_TPM) && defined(WOLFBOOT_TPM_VERIFY) +static void wolfBoot_verify_signature(uint8_t key_slot, + struct wolfBoot_image *img, uint8_t *sig) +{ + int ret, verify_res = 0; + WOLFTPM2_KEY tpmKey; + TPM_ALG_ID alg, sigAlg; + + /* Load public key into TPM */ + memset(&tpmKey, 0, sizeof(tpmKey)); + + /* get public key for policy authorization */ + ret = wolfBoot_load_pubkey(img, &tpmKey, &alg); + if (ret == 0) { + sigAlg = (alg == TPM_ALG_RSA) ? TPM_ALG_RSASSA : TPM_ALG_ECDSA; + ret = wolfTPM2_VerifyHashScheme(&wolftpm_dev, &tpmKey, + sig, IMAGE_SIGNATURE_SIZE, /* Signature */ + img->sha_hash, WOLFBOOT_SHA_DIGEST_SIZE, /* Hash */ + sigAlg, WOLFBOOT_TPM_HASH_ALG); + } + /* unload handle regardless of result */ + wolfTPM2_UnloadHandle(&wolftpm_dev, &tpmKey.handle); + + if (ret == 0) { + verify_res = 1; /* TPM does hash verify compare */ + + if ((~(uint32_t)ret == 0xFFFFFFFF) && (verify_res == 1) && + (~(uint32_t)verify_res == 0xFFFFFFFE)) { + wolfBoot_image_confirm_signature_ok(img); + } + } + else { + wolfBoot_printf("TPM verify signature error %d (%s)\n", + ret, wolfTPM2_GetRCString(ret)); + } + (void)key_slot; +} +#else +/* wolfCrypt software verify */ #ifdef WOLFBOOT_SIGN_ED25519 #include static void wolfBoot_verify_signature(uint8_t key_slot, @@ -123,54 +163,18 @@ static void wolfBoot_verify_signature(uint8_t key_slot, uint8_t *pubkey = keystore_get_buffer(key_slot); int pubkey_sz = keystore_get_size(key_slot); int point_sz = pubkey_sz/2; -#if defined(WOLFBOOT_TPM) && defined(WOLFBOOT_TPM_VERIFY) - WOLFTPM2_KEY tpmKey; -#else ecc_key ecc; mp_int r, s; -#endif if (pubkey == NULL || pubkey_sz <= 0) { return; } -#if defined(WOLFBOOT_TPM) && defined(WOLFBOOT_TPM_VERIFY) - /* Use TPM for ECC verify */ - /* Load public key into TPM */ - memset(&tpmKey, 0, sizeof(tpmKey)); - ret = wolfTPM2_LoadEccPublicKey(&wolftpm_dev, &tpmKey, - TPM2_GetTpmCurve(ECC_KEY_TYPE), /* Curve */ - pubkey, point_sz, /* Public X */ - pubkey + point_sz, point_sz /* Public Y */ - ); - if (ret == 0) { - ret = wolfTPM2_VerifyHashScheme(&wolftpm_dev, &tpmKey, - sig, IMAGE_SIGNATURE_SIZE, /* Signature */ - img->sha_hash, WOLFBOOT_SHA_DIGEST_SIZE, /* Hash */ - TPM_ALG_ECDSA, WOLFBOOT_TPM_HASH_ALG); - } - /* unload handle regardless of result */ - wolfTPM2_UnloadHandle(&wolftpm_dev, &tpmKey.handle); - - if (ret == 0) { - verify_res = 1; /* TPM does hash verify compare */ - - if ((~(uint32_t)ret == 0xFFFFFFFF) && (verify_res == 1) && - (~(uint32_t)verify_res == 0xFFFFFFFE)) { - wolfBoot_image_confirm_signature_ok(img); - } - } - else { - wolfBoot_printf("TPM ECC verify error %d (%s)\n", - ret, wolfTPM2_GetRCString(ret)); - } -#else - /* wolfCrypt software ECC verify */ ret = wc_ecc_init(&ecc); if (ret == 0) { /* Import public key */ - ret = wc_ecc_import_unsigned(&ecc, pubkey, - (byte*)(pubkey + point_sz), NULL, ECC_KEY_TYPE); + ret = wc_ecc_import_unsigned(&ecc, pubkey, pubkey + point_sz, NULL, + ECC_KEY_TYPE); if (ret == 0 && ecc.type == ECC_PUBLICKEY) { /* Import signature into r,s */ mp_init(&r); @@ -182,7 +186,6 @@ static void wolfBoot_verify_signature(uint8_t key_slot, } wc_ecc_free(&ecc); } -#endif /* WOLFBOOT_TPM && WOLFBOOT_TPM_VERIFY*/ } #endif /* WOLFBOOT_SIGN_ECC256 || WOLFBOOT_SIGN_ECC384 || WOLFBOOT_SIGN_ECC521 */ @@ -247,31 +250,6 @@ static int RsaDecodeSignature(uint8_t** pInput, int inputSz) } #endif /* !NO_RSA_SIG_ENCODING */ -#if defined(WOLFBOOT_TPM) && defined(WOLFBOOT_TPM_VERIFY) -/* RSA PKCSV15 un-padding with RSA_BLOCK_TYPE_1 (public) */ -/* UnPad plaintext, set start to *output, return length of plaintext or error */ -static int RsaUnPad(const byte *pkcsBlock, int pkcsBlockLen, byte **output) -{ - int ret = BAD_FUNC_ARG, i; - if (output == NULL || pkcsBlockLen < 2 || pkcsBlockLen > 0xFFFF) { - return BAD_FUNC_ARG; - } - /* First byte must be 0x00 and Second byte, block type, 0x01 */ - if (pkcsBlock[0] != 0 || pkcsBlock[1] != RSA_BLOCK_TYPE_1) { - return RSA_PAD_E; - } - /* check the padding until we find the separator */ - for (i = 2; i < pkcsBlockLen && pkcsBlock[i++] == 0xFF; ) { } - /* Minimum of 11 bytes of pre-message data and must have separator. */ - if (i < RSA_MIN_PAD_SZ || pkcsBlock[i-1] != 0) { - return RSA_PAD_E; - } - *output = (byte *)(pkcsBlock + i); - ret = pkcsBlockLen - i; - return ret; -} -#endif /* WOLFBOOT_TPM && WOLFBOOT_TPM_VERIFY*/ - static void wolfBoot_verify_signature(uint8_t key_slot, struct wolfBoot_image *img, uint8_t *sig) { @@ -282,53 +260,12 @@ static void wolfBoot_verify_signature(uint8_t key_slot, uint8_t *pubkey = keystore_get_buffer(key_slot); int pubkey_sz = keystore_get_size(key_slot); word32 inOutIdx = 0; -#if defined(WOLFBOOT_TPM) && defined(WOLFBOOT_TPM_VERIFY) - WOLFTPM2_KEY tpmKey; - const byte *n = NULL, *e = NULL; - word32 nSz = 0, eSz = 0; -#else struct RsaKey rsa; -#endif if (pubkey == NULL || pubkey_sz < 0) { return; } -#if defined(WOLFBOOT_TPM) && defined(WOLFBOOT_TPM_VERIFY) - /* Extract DER RSA key struct */ - memset(&tpmKey, 0, sizeof(tpmKey)); - ret = wc_RsaPublicKeyDecode_ex(pubkey, &inOutIdx, pubkey_sz, - &n, &nSz, /* modulus */ - &e, &eSz /* exponent */ - ); - if (ret == 0) { - /* Load public key into TPM */ - memset(&tpmKey, 0, sizeof(tpmKey)); - ret = wolfTPM2_LoadRsaPublicKey_ex(&wolftpm_dev, &tpmKey, - n, nSz, *((word32*)e), - TPM_ALG_NULL, WOLFBOOT_TPM_HASH_ALG); - } - if (ret == 0) { - /* Perform public decrypt and manually un-pad */ - ret = wolfTPM2_RsaEncrypt(&wolftpm_dev, &tpmKey, - TPM_ALG_NULL, /* no padding */ - sig, IMAGE_SIGNATURE_SIZE, - output, &output_sz); - } - if (ret == 0) { - /* Perform PKCSv1.5 UnPadding */ - ret = RsaUnPad(output, output_sz, &digest_out); - } - - if (ret < 0) { - wolfBoot_printf("TPM RSA error %d (%s)\n", - ret, wolfTPM2_GetRCString(ret)); - return; - } - - wolfTPM2_UnloadHandle(&wolftpm_dev, &tpmKey.handle); - -#else /* wolfCrypt software RSA verify */ #if defined(WOLFBOOT_RENESAS_SCEPROTECT) ||\ defined(WOLFBOOT_RENESAS_TSIP) @@ -357,7 +294,6 @@ static void wolfBoot_verify_signature(uint8_t key_slot, } #endif /* SCE || TSIP */ wc_FreeRsaKey(&rsa); -#endif /* WOLFBOOT_TPM && WOLFBOOT_TPM_VERIFY*/ #ifndef NO_RSA_SIG_ENCODING if (ret > WOLFBOOT_SHA_DIGEST_SIZE) { @@ -438,6 +374,8 @@ static void wolfBoot_verify_signature(uint8_t key_slot, } #endif /* WOLFBOOT_SIGN_LMS */ +#endif /* WOLFBOOT_TPM && WOLFBOOT_TPM_VERIFY */ + /** * @brief Get the specified header type from the external flash image. diff --git a/src/tpm.c b/src/tpm.c index 053951592..2d02b52f0 100644 --- a/src/tpm.c +++ b/src/tpm.c @@ -308,18 +308,16 @@ int wolfBoot_tpm2_extend(uint8_t pcrIndex, uint8_t* hash, int line) rc = wolfTPM2_ExtendPCR(&wolftpm_dev, pcrIndex, WOLFBOOT_TPM_PCR_ALG, hash, TPM2_GetHashDigestSize(WOLFBOOT_TPM_PCR_ALG)); -#ifdef DEBUG_WOLFTPM +#ifdef WOLFBOOT_DEBUG_TPM if (rc == 0) { wolfBoot_printf("Measured boot: Index %d, Line %d\n", pcrIndex, line); - #ifdef WOLFBOOT_DEBUG_TPM rc = wolfTPM2_ReadPCR(&wolftpm_dev, pcrIndex, WOLFBOOT_TPM_PCR_ALG, digest, &digestSz); wolfBoot_printf("PCR %d: Res %d, Digest Sz %d\n", pcrIndex, rc, digestSz); wolfBoot_print_bin(digest, digestSz); - #endif } else { wolfBoot_printf("Measure boot failed! Index %d, %x (%s)\n", @@ -332,6 +330,83 @@ int wolfBoot_tpm2_extend(uint8_t pcrIndex, uint8_t* hash, int line) } #endif /* WOLFBOOT_MEASURED_BOOT */ +#if defined(WOLFBOOT_TPM_VERIFY) || defined(WOLFBOOT_TPM_SEAL) +int wolfBoot_load_pubkey(struct wolfBoot_image* img, WOLFTPM2_KEY* pubKey, + TPM_ALG_ID* pAlg) +{ + int rc = 0; + uint32_t key_type; + int key_slot = -1; + uint8_t *hdr; + uint16_t hdrSz; + + *pAlg = TPM_ALG_NULL; + + /* get public key */ + hdrSz = wolfBoot_get_header(img, HDR_PUBKEY, &hdr); + if (hdrSz == WOLFBOOT_SHA_DIGEST_SIZE) + key_slot = keyslot_id_by_sha(hdr); + if (key_slot < 0) + rc = -1; + + if (rc == 0) { + key_type = keystore_get_key_type(key_slot); + hdr = keystore_get_buffer(key_slot); + hdrSz = keystore_get_size(key_slot); + if (hdr == NULL || hdrSz <= 0) + rc = -1; + } + /* Parse public key to TPM public key. Note: this loads as temp handle, + * however we don't use the handle. We still need to unload it. */ + if (rc == 0) { + #if defined(WOLFBOOT_SIGN_ECC256) || \ + defined(WOLFBOOT_SIGN_ECC384) || \ + defined(WOLFBOOT_SIGN_ECC521) + int tpmcurve; + int point_sz = hdrSz/2; + if ( key_type == AUTH_KEY_ECC256) tpmcurve = TPM_ECC_NIST_P256; + else if (key_type == AUTH_KEY_ECC384) tpmcurve = TPM_ECC_NIST_P384; + else if (key_type == AUTH_KEY_ECC521) tpmcurve = TPM_ECC_NIST_P521; + else rc = -1; /* not supported algorithm */ + if (rc == 0) { + *pAlg = TPM_ALG_ECC; + rc = wolfTPM2_LoadEccPublicKey(&wolftpm_dev, pubKey, + tpmcurve, /* Curve */ + hdr, point_sz, /* Public X */ + hdr + point_sz, point_sz /* Public Y */ + ); + } + #elif defined(WOLFBOOT_SIGN_RSA2048) || \ + defined(WOLFBOOT_SIGN_RSA3072) || \ + defined(WOLFBOOT_SIGN_RSA4096) + uint32_t inOutIdx = 0; + const uint8_t*n = NULL, *e = NULL; + uint32_t nSz = 0, eSz = 0; + if (key_type != AUTH_KEY_RSA2048 && key_type != AUTH_KEY_RSA3072 && + key_type != AUTH_KEY_RSA4096) { + rc = -1; + } + if (rc == 0) { + *pAlg = TPM_ALG_RSA; + rc = wc_RsaPublicKeyDecode_ex(hdr, &inOutIdx, hdrSz, + &n, &nSz, /* modulus */ + &e, &eSz /* exponent */ + ); + } + if (rc == 0) { + /* Load public key into TPM */ + rc = wolfTPM2_LoadRsaPublicKey_ex(&wolftpm_dev, pubKey, + n, nSz, *((uint32_t*)e), + TPM_ALG_NULL, WOLFBOOT_TPM_HASH_ALG); + } + #else + rc = -1; /* not supported */ + #endif + } + return rc; +} +#endif /* WOLFBOOT_TPM_VERIFY || WOLFBOOT_TPM_SEAL */ + #ifdef WOLFBOOT_TPM_SEAL int wolfBoot_get_random(uint8_t* buf, int sz) { @@ -495,77 +570,136 @@ int wolfBoot_get_policy(struct wolfBoot_image* img, return rc; } -int wolfBoot_load_pubkey(struct wolfBoot_image* img, WOLFTPM2_KEY* pubKey, - TPM_ALG_ID* pAlg) +/* authHandle = TPM_RH_PLATFORM or TPM_RH_OWNER */ +/* auth is optional */ +int wolfBoot_store_blob(TPMI_RH_NV_AUTH authHandle, uint32_t nvIndex, + word32 nvAttributes, WOLFTPM2_KEYBLOB* blob, + const uint8_t* auth, uint32_t authSz) { - int rc = 0; - uint32_t key_type; - int key_slot = -1; - uint8_t *hdr; - uint16_t hdrSz; + int rc; + WOLFTPM2_HANDLE parent; + WOLFTPM2_NV nv; + uint8_t pubAreaBuffer[sizeof(TPM2B_PUBLIC)]; /* oversized buffer */ + int nvSz, pos, pubAreaSize; - *pAlg = TPM_ALG_NULL; + memset(&parent, 0, sizeof(parent)); + memset(&nv, 0, sizeof(nv)); - /* get public key */ - hdrSz = wolfBoot_get_header(img, HDR_PUBKEY, &hdr); - if (hdrSz == WOLFBOOT_SHA_DIGEST_SIZE) - key_slot = keyslot_id_by_sha(hdr); - if (key_slot < 0) - rc = -1; + nv.handle.hndl = nvIndex; + nv.handle.auth.size = authSz; + memcpy(nv.handle.auth.buffer, auth, authSz); + parent.hndl = authHandle; + + /* encode public for smaller storage */ + rc = TPM2_AppendPublic(pubAreaBuffer, (word32)sizeof(pubAreaBuffer), + &pubAreaSize, &blob->pub); if (rc == 0) { - key_type = keystore_get_key_type(key_slot); - hdr = keystore_get_buffer(key_slot); - hdrSz = keystore_get_size(key_slot); - if (hdr == NULL || hdrSz <= 0) - rc = -1; + blob->pub.size = pubAreaSize; + + nvSz = (uint32_t)sizeof(blob->pub.size) + blob->pub.size; + nvSz += (uint32_t)sizeof(blob->priv.size) + blob->priv.size; + + /* Create NV - no auth required, blob encrypted by TPM already */ + rc = wolfTPM2_NVCreateAuth(&wolftpm_dev, &parent, &nv, + nv.handle.hndl, nvAttributes, nvSz, NULL, 0); + if (rc == TPM_RC_NV_DEFINED) { + /* allow use of existing handle - ignore this error */ + rc = 0; + } } - /* Parse public key to TPM public key. Note: this loads as temp handle, - * however we don't use the handle. We still need to unload it. */ + /* write sealed blob to NV */ if (rc == 0) { - #if defined(WOLFBOOT_SIGN_ECC256) || \ - defined(WOLFBOOT_SIGN_ECC384) || \ - defined(WOLFBOOT_SIGN_ECC521) - int tpmcurve; - int point_sz = hdrSz/2; - if ( key_type == AUTH_KEY_ECC256) tpmcurve = TPM_ECC_NIST_P256; - else if (key_type == AUTH_KEY_ECC384) tpmcurve = TPM_ECC_NIST_P384; - else if (key_type == AUTH_KEY_ECC521) tpmcurve = TPM_ECC_NIST_P521; - else rc = -1; /* not supported algorithm */ - if (rc == 0) { - *pAlg = TPM_ALG_ECC; - rc = wolfTPM2_LoadEccPublicKey(&wolftpm_dev, pubKey, - tpmcurve, /* Curve */ - hdr, point_sz, /* Public X */ - hdr + point_sz, point_sz /* Public Y */ - ); - } - #elif defined(WOLFBOOT_SIGN_RSA2048) || \ - defined(WOLFBOOT_SIGN_RSA3072) || \ - defined(WOLFBOOT_SIGN_RSA4096) - uint32_t inOutIdx = 0; - const uint8_t*n = NULL, *e = NULL; - uint32_t nSz = 0, eSz = 0; - if (key_type != AUTH_KEY_RSA2048 && key_type != AUTH_KEY_RSA3072 && - key_type != AUTH_KEY_RSA4096) { - rc = -1; - } - if (rc == 0) { - *pAlg = TPM_ALG_RSA; - rc = wc_RsaPublicKeyDecode_ex(hdr, &inOutIdx, hdrSz, - &n, &nSz, /* modulus */ - &e, &eSz /* exponent */ - ); - } - if (rc == 0) { - /* Load public key into TPM */ - rc = wolfTPM2_LoadRsaPublicKey_ex(&wolftpm_dev, pubKey, - n, nSz, *((uint32_t*)e), - TPM_ALG_NULL, WOLFBOOT_TPM_HASH_ALG); - } - #else - rc = -1; /* not supported */ - #endif + pos = 0; + /* write pub size */ + rc = wolfTPM2_NVWriteAuth(&wolftpm_dev, &nv, nv.handle.hndl, + (uint8_t*)&blob->pub.size, + (uint32_t)sizeof(blob->pub.size), pos); + } + if (rc == 0) { + pos += sizeof(blob->pub.size); + /* write pub */ + rc = wolfTPM2_NVWriteAuth(&wolftpm_dev, &nv, nv.handle.hndl, + pubAreaBuffer, blob->pub.size, pos); + } + if (rc == 0) { + pos += blob->pub.size; + /* write priv size */ + rc = wolfTPM2_NVWriteAuth(&wolftpm_dev, &nv, nv.handle.hndl, + (uint8_t*)&blob->priv.size, + (uint32_t)sizeof(blob->priv.size), pos); + } + if (rc == 0) { + pos += sizeof(blob->priv.size); + /* write priv */ + rc = wolfTPM2_NVWriteAuth(&wolftpm_dev, &nv, nv.handle.hndl, + blob->priv.buffer, blob->priv.size, pos); + } + if (rc == 0) { + pos += blob->priv.size; + } + if (rc == 0) { + wolfBoot_printf("Wrote %d bytes to NV index 0x%x\n", + pos, nv.handle.hndl); + } + else { + wolfBoot_printf("Error %d writing blob to NV index %x (error %s)\n", + rc, nv.handle.hndl, wolfTPM2_GetRCString(rc)); + } + return rc; +} + +int wolfBoot_read_blob(uint32_t nvIndex, WOLFTPM2_KEYBLOB* blob, + const uint8_t* auth, uint32_t authSz) +{ + int rc; + WOLFTPM2_NV nv; + uint8_t pubAreaBuffer[sizeof(TPM2B_PUBLIC)]; + uint32_t readSz; + int nvSz, pubAreaSize = 0, pos; + + memset(&nv, 0, sizeof(nv)); + + nv.handle.hndl = nvIndex; + nv.handle.auth.size = authSz; + memcpy(nv.handle.auth.buffer, auth, authSz); + + pos = 0; + readSz = sizeof(blob->pub.size); + rc = wolfTPM2_NVReadAuth(&wolftpm_dev, &nv, nv.handle.hndl, + (uint8_t*)&blob->pub.size, &readSz, pos); + if (rc == 0) { + pos += readSz; + readSz = blob->pub.size; + rc = wolfTPM2_NVReadAuth(&wolftpm_dev, &nv, nv.handle.hndl, + pubAreaBuffer, &readSz, pos); + } + if (rc == 0) { + pos += readSz; + rc = TPM2_ParsePublic(&blob->pub, pubAreaBuffer, + (word32)sizeof(pubAreaBuffer), &pubAreaSize); + } + if (rc == 0) { + readSz = sizeof(blob->priv.size); + rc = wolfTPM2_NVReadAuth(&wolftpm_dev, &nv, nv.handle.hndl, + (uint8_t*)&blob->priv.size, &readSz, pos); + } + if (rc == 0) { + pos += sizeof(blob->priv.size); + readSz = blob->priv.size; + rc = wolfTPM2_NVReadAuth(&wolftpm_dev, &nv, nv.handle.hndl, + blob->priv.buffer, &readSz, pos); + } + if (rc == 0) { + pos += blob->priv.size; + } + if (rc == 0) { + wolfBoot_printf("Read %d bytes from NV index 0x%x\n", + pos, nv.handle.hndl); + } + else { + wolfBoot_printf("Error %d reading blob from NV index %x (error %s)\n", + rc, nv.handle.hndl, wolfTPM2_GetRCString(rc)); } return rc; } @@ -642,6 +776,7 @@ int wolfBoot_seal_blob(struct wolfBoot_image* img, WOLFTPM2_KEYBLOB* seal_blob, } wolfTPM2_UnloadHandle(&wolftpm_dev, &policy_session.handle); + wolfTPM2_UnsetAuth(&wolftpm_dev, 1); return rc; } @@ -653,22 +788,31 @@ int wolfBoot_seal(struct wolfBoot_image* img, int index, { int rc; WOLFTPM2_KEYBLOB seal_blob; + word32 nvAttributes; + memset(&seal_blob, 0, sizeof(seal_blob)); + /* creates a sealed keyed hash object (not loaded to TPM) */ rc = wolfBoot_seal_blob(img, &seal_blob, secret, secret_sz); if (rc == 0) { #ifdef WOLFBOOT_DEBUG_TPM wolfBoot_printf("Sealed keyed hash (pub %d, priv %d bytes):\n", seal_blob.pub.size, seal_blob.priv.size); - //wolfBoot_print_bin((uint8_t*)&seal_blob.pub, (uint32_t)sizeof(seal_blob.pub)); - //wolfBoot_print_bin(seal_blob.priv.buffer, seal_blob.priv.size); #endif - /* TODO: store sealed blob in TPM NV */ - (void)index; - //wolfTPM2_GetNvAttributesTemplate - //wolfTPM2_NVCreateAuth - //wolfTPM2_NVWriteAuth + /* Get NV attributes amd allow it to be locked (if desired) */ + wolfTPM2_GetNvAttributesTemplate(TPM_RH_PLATFORM, &nvAttributes); + nvAttributes |= TPMA_NV_WRITEDEFINE; + + rc = wolfBoot_store_blob(TPM_RH_PLATFORM, + WOLFBOOT_TPM_SEAL_NV_BASE + index, + nvAttributes, &seal_blob, + NULL, 0 /* auth is not required as sealed blob is already encrypted */ + ); + } + if (rc != 0) { + wolfBoot_printf("Error %d sealing secret! (%s)\n", + rc, wolfTPM2_GetRCString(rc)); } return rc; } @@ -817,30 +961,35 @@ int wolfBoot_unseal_blob(struct wolfBoot_image* img, WOLFTPM2_KEYBLOB* seal_blob wolfTPM2_UnloadHandle(&wolftpm_dev, &seal_blob->handle); wolfTPM2_UnloadHandle(&wolftpm_dev, &policy_session.handle); + wolfTPM2_UnsetAuth(&wolftpm_dev, 1); return rc; } -int wolfBoot_unseal(struct wolfBoot_image* img, int index, uint8_t* secret, int* secret_sz) +int wolfBoot_unseal(struct wolfBoot_image* img, int index, uint8_t* secret, + int* secret_sz) { int rc; WOLFTPM2_KEYBLOB seal_blob; - memset(&seal_blob, 0, sizeof(seal_blob)); - /* TODO: get sealed blob in TPM NV */ - (void)index; - //wolfTPM2_NVReadPublic - //wolfTPM2_NVReadAuth + memset(&seal_blob, 0, sizeof(seal_blob)); - rc = wolfBoot_unseal_blob(img, &seal_blob, secret, secret_sz); + rc = wolfBoot_read_blob(WOLFBOOT_TPM_SEAL_NV_BASE + index, &seal_blob, + NULL, 0 /* auth is not required as sealed blob is already encrypted */ + ); if (rc == 0) { + rc = wolfBoot_unseal_blob(img, &seal_blob, secret, secret_sz); #ifdef WOLFBOOT_DEBUG_TPM - wolfBoot_printf("Unsealed keyed hash (pub %d, priv %d bytes):\n", - seal_blob.pub.size, seal_blob.priv.size); - //wolfBoot_print_bin((uint8_t*)&seal_blob.pub, (uint32_t)sizeof(seal_blob.pub)); - //wolfBoot_print_bin(seal_blob.priv.buffer, seal_blob.priv.size); + if (rc == 0) { + wolfBoot_printf("Unsealed keyed hash (pub %d, priv %d bytes):\n", + seal_blob.pub.size, seal_blob.priv.size); + } #endif } + if (rc != 0) { + wolfBoot_printf("Error %d unsealing secret! (%s)\n", + rc, wolfTPM2_GetRCString(rc)); + } return rc; } #endif /* WOLFBOOT_TPM_SEAL */ @@ -1009,8 +1158,7 @@ int wolfBoot_check_rot(int key_slot, uint8_t* pubkey_hint) rc = wolfTPM2_SetAuthSession(&wolftpm_dev, 1, &wolftpm_session, (TPMA_SESSION_decrypt | TPMA_SESSION_encrypt | TPMA_SESSION_continueSession)); - if (rc == 0) - { + if (rc == 0) { /* find index with matching digest */ nv.handle.hndl = WOLFBOOT_TPM_KEYSTORE_NV_BASE + key_slot; rc = wolfTPM2_NVReadAuth(&wolftpm_dev, &nv, nv.handle.hndl, @@ -1020,11 +1168,11 @@ int wolfBoot_check_rot(int key_slot, uint8_t* pubkey_hint) wolfBoot_printf("TPM Root of Trust valid (id %d)\n", key_slot); } else { + if (rc >= 0) rc = -1; /* failure */ wolfBoot_printf("TPM Root of Trust failed! %d (%s)\n", rc, wolfTPM2_GetRCString(rc)); wolfBoot_printf("Expected Hash %d\n", digestSz); wolfBoot_print_hexstr(pubkey_hint, digestSz, 0); - if (rc >= 0) rc = -1; /* failure */ } } wolfTPM2_UnsetAuth(&wolftpm_dev, 1); diff --git a/src/update_flash.c b/src/update_flash.c index 4fb765db6..67dbfcbda 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -575,13 +575,12 @@ int wolfBoot_unlock_disk(void) { int ret; struct wolfBoot_image img; - WOLFTPM2_KEYBLOB seal_blob; uint8_t secret[WOLFBOOT_MAX_SEAL_SZ]; int secretSz; uint8_t* policy = NULL; uint16_t policySz = 0; + int nvIndex = 0; /* where the sealed blob is stored in NV */ - memset(&seal_blob, 0, sizeof(seal_blob)); memset(secret, 0, sizeof(secret)); wolfBoot_printf("Unlocking disk...\n"); @@ -597,38 +596,49 @@ int wolfBoot_unlock_disk(void) } } if (ret == 0) { - /* for testing seal and unseal */ - /* create secret to seal */ - secretSz = 32; - ret = wolfBoot_get_random(secret, secretSz); - if (ret == 0) { - wolfBoot_printf("Sealing %d bytes\n", secretSz); - wolfBoot_print_hexstr(secret, secretSz, 0); - - /* seal new secret */ - ret = wolfBoot_seal_blob(&img, &seal_blob, secret, secretSz); - } - if (ret == 0) { - uint8_t secretCheck[WOLFBOOT_MAX_SEAL_SZ]; - int secretCheckSz = 0; + /* try to unseal the secret */ + ret = wolfBoot_unseal(&img, nvIndex, secret, &secretSz); + if (ret != 0) { /* if secret does not exist, expect TPM_RC_HANDLE here */ + if ((ret & RC_MAX_FMT1) == TPM_RC_HANDLE) { + wolfBoot_printf("Sealed secret does not exist!\n"); + } + /* create secret to seal */ + secretSz = 32; + ret = wolfBoot_get_random(secret, secretSz); + if (ret == 0) { + wolfBoot_printf("Creating new secret (%d bytes)\n", secretSz); + wolfBoot_print_hexstr(secret, secretSz, 0); - /* unseal again to make sure it works */ - memset(secretCheck, 0, sizeof(secretCheck)); - ret = wolfBoot_unseal_blob(&img, &seal_blob, secretCheck, &secretCheckSz); + /* seal new secret */ + ret = wolfBoot_seal(&img, nvIndex, secret, secretSz); + } if (ret == 0) { - if (secretSz != secretCheckSz || memcmp(secret, secretCheck, secretSz) != 0) { - wolfBoot_printf("secret check mismatch!\n"); - ret = -1; + uint8_t secretCheck[WOLFBOOT_MAX_SEAL_SZ]; + int secretCheckSz = 0; + + /* unseal again to make sure it works */ + memset(secretCheck, 0, sizeof(secretCheck)); + ret = wolfBoot_unseal(&img, nvIndex, secretCheck, &secretCheckSz); + if (ret == 0) { + if (secretSz != secretCheckSz || + memcmp(secret, secretCheck, secretSz) != 0) + { + wolfBoot_printf("secret check mismatch!\n"); + ret = -1; + } } - } - wolfBoot_printf("Unsealed %d bytes\n", secretCheckSz); - wolfBoot_print_hexstr(secretCheck, secretCheckSz, 0); - TPM2_ForceZero(secretCheck, sizeof(secretCheck)); + wolfBoot_printf("Secret Check %d bytes\n", secretCheckSz); + wolfBoot_print_hexstr(secretCheck, secretCheckSz, 0); + TPM2_ForceZero(secretCheck, sizeof(secretCheck)); + } } } if (ret == 0) { + wolfBoot_printf("Secret %d bytes\n", secretSz); + wolfBoot_print_hexstr(secret, secretSz, 0); + /* TODO: Unlock disk */ }