Repository navigation
Fixes for Firmware TPM issues and related session, clock and signature defects #656
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
3ff7ad4
0a50945
5f5cc14
1148123
d5038fc
0635bed
201d8e3
211d2bc
c40d63f
fa179ac
6087cfe
a341fd2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| #!/bin/bash | ||
| # tpm2_pkcs11_test.sh | ||
| # Run tpm2-pkcs11 (tpm2_ptool + OpenSC pkcs11-tool) against a running TPM, | ||
| # either directly or through tpm2-abrmd. | ||
| # | ||
| # Usage: | ||
| # scripts/tpm2_pkcs11_test.sh | ||
| # | ||
| # Environment: | ||
| # TPM2_PKCS11_TCTI TCTI for tpm2-pkcs11 and tpm2_ptool | ||
| # (default: mssim:host=localhost,port=2321; | ||
| # use tabrmd:bus_type=session behind tpm2-abrmd) | ||
| # PKCS11_MODULE path to libtpm2_pkcs11.so (default: searched) | ||
| # | ||
| # Requirements: tpm2-pkcs11 (libtpm2_pkcs11.so, tpm2_ptool), OpenSC | ||
| # pkcs11-tool, openssl | ||
| # | ||
| # Exit: 0 if all tests pass, 77 if a requirement is missing (SKIP), 1 on failure | ||
|
|
||
| TPM2_PKCS11_TCTI="${TPM2_PKCS11_TCTI:-mssim:host=localhost,port=2321}" | ||
| export TPM2_PKCS11_TCTI | ||
| export TPM2TOOLS_TCTI="$TPM2_PKCS11_TCTI" | ||
|
|
||
| if [ -z "$PKCS11_MODULE" ]; then | ||
| PKCS11_MODULE=$(find /usr/lib /usr/local/lib -name 'libtpm2_pkcs11.so*' \ | ||
| 2>/dev/null | head -1) | ||
| fi | ||
| for tool in tpm2_ptool tpm2_flushcontext pkcs11-tool openssl; do | ||
| if ! command -v "$tool" >/dev/null 2>&1; then | ||
| echo "SKIP: $tool not installed" | ||
| exit 77 | ||
| fi | ||
| done | ||
| if [ -z "$PKCS11_MODULE" ] || [ ! -f "$PKCS11_MODULE" ]; then | ||
| echo "SKIP: libtpm2_pkcs11.so not found" | ||
| exit 77 | ||
| fi | ||
|
|
||
| PIN=1234 | ||
| SOPIN=5678 | ||
| LABEL=wolftpm | ||
| TMP=$(mktemp -d) | ||
| export TPM2_PKCS11_STORE="$TMP/store" | ||
| mkdir -p "$TPM2_PKCS11_STORE" | ||
| trap 'rm -rf "$TMP"' EXIT | ||
|
|
||
| PASS=0 | ||
| FAIL=0 | ||
|
|
||
| run_test() { | ||
| local name="$1" | ||
| shift | ||
| if "$@" > "$TMP/out.log" 2>&1; then | ||
| echo " [PASS] $name" | ||
| PASS=$((PASS+1)) | ||
| else | ||
| echo " [FAIL] $name" | ||
| sed 's/^/ /' "$TMP/out.log" | ||
| FAIL=$((FAIL+1)) | ||
| fi | ||
| } | ||
|
|
||
| # Without a resource manager, tpm2-tools and tpm2-pkcs11 leave objects and | ||
| # sessions loaded when they exit. Flush them so later steps have free slots. | ||
| flush_tpm() { | ||
| case "$TPM2_PKCS11_TCTI" in | ||
| tabrmd*) ;; | ||
| *) | ||
| tpm2_flushcontext -t > /dev/null 2>&1 | ||
| tpm2_flushcontext -l > /dev/null 2>&1 | ||
| ;; | ||
| esac | ||
| } | ||
|
|
||
| ptool() { | ||
| tpm2_ptool "$@" | ||
| local rc=$? | ||
| flush_tpm | ||
| return $rc | ||
| } | ||
|
|
||
| p11() { | ||
| pkcs11-tool --module "$PKCS11_MODULE" --token-label "$LABEL" \ | ||
| --login --pin "$PIN" "$@" | ||
| local rc=$? | ||
| flush_tpm | ||
| return $rc | ||
| } | ||
|
|
||
| echo "=== tpm2-pkcs11 tests (TCTI: $TPM2_PKCS11_TCTI) ===" | ||
|
|
||
| run_test "ptool init" ptool init | ||
| run_test "ptool addtoken" ptool addtoken --pid=1 --label="$LABEL" \ | ||
| --userpin="$PIN" --sopin="$SOPIN" | ||
| run_test "ptool addkey ecc256" ptool addkey --label="$LABEL" \ | ||
| --userpin="$PIN" --algorithm=ecc256 --key-label=ecc --id=01 | ||
| run_test "ptool addkey rsa2048" ptool addkey --label="$LABEL" \ | ||
| --userpin="$PIN" --algorithm=rsa2048 --key-label=rsa --id=02 | ||
|
|
||
| run_test "list objects" p11 --list-objects | ||
|
|
||
| # Keys are selected by CKA_ID (the ASCII bytes of the tpm2_ptool --id); | ||
| # a label match can return another key | ||
| # Export public keys for software verification | ||
| run_test "read ECC public key" p11 --read-object --type pubkey --id 3031 \ | ||
| --output-file "$TMP/ecc.der" | ||
| run_test "read RSA public key" p11 --read-object --type pubkey --id 3032 \ | ||
| --output-file "$TMP/rsa.der" | ||
|
|
||
| # ECDSA (CKM_ECDSA_SHA256) sign, verified by OpenSSL | ||
| printf 'wolfTPM tpm2-pkcs11 test' > "$TMP/msg.bin" | ||
| run_test "ECDSA-SHA256 sign" p11 --sign --mechanism ECDSA-SHA256 --id 3031 \ | ||
| --signature-format openssl --input-file "$TMP/msg.bin" \ | ||
| --output-file "$TMP/ecc.sig" | ||
| run_test "ECDSA-SHA256 verify (OpenSSL)" openssl dgst -sha256 \ | ||
| -verify "$TMP/ecc.der" -keyform DER -signature "$TMP/ecc.sig" \ | ||
| "$TMP/msg.bin" | ||
|
|
||
| # CKM_ECDSA of an all-zero digest, as for an empty message padded to the | ||
| # hash length | ||
| head -c 32 /dev/zero > "$TMP/zero.bin" | ||
| run_test "ECDSA sign of an all-zero digest" p11 --sign --mechanism ECDSA \ | ||
| --id 3031 --input-file "$TMP/zero.bin" --output-file "$TMP/zero.sig" | ||
|
|
||
| # RSA-PKCS#1 v1.5 sign, verified by OpenSSL | ||
| run_test "RSA-SHA256 sign" p11 --sign --mechanism SHA256-RSA-PKCS --id 3032 \ | ||
| --input-file "$TMP/msg.bin" --output-file "$TMP/rsa.sig" | ||
| run_test "RSA-SHA256 verify (OpenSSL)" openssl dgst -sha256 \ | ||
| -verify "$TMP/rsa.der" -keyform DER -signature "$TMP/rsa.sig" \ | ||
| "$TMP/msg.bin" | ||
|
|
||
| # RSA-OAEP (SHA-256) encrypted by OpenSSL, decrypted by the TPM | ||
| printf 'oaep plaintext' > "$TMP/pt.bin" | ||
| run_test "RSA-OAEP encrypt (OpenSSL)" openssl pkeyutl -encrypt -pubin \ | ||
| -keyform DER -inkey "$TMP/rsa.der" -in "$TMP/pt.bin" -out "$TMP/ct.bin" \ | ||
| -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 \ | ||
| -pkeyopt rsa_mgf1_md:sha256 | ||
| run_test "RSA-OAEP decrypt" p11 --decrypt --mechanism RSA-PKCS-OAEP \ | ||
| --hash-algorithm SHA256 --mgf MGF1-SHA256 --id 3032 \ | ||
| --input-file "$TMP/ct.bin" --output-file "$TMP/dec.bin" | ||
| run_test "RSA-OAEP plaintext matches" cmp "$TMP/pt.bin" "$TMP/dec.bin" | ||
|
|
||
| # RSA-OAEP with SHA-1 and MGF1-SHA-1 | ||
| run_test "RSA-OAEP-SHA1 encrypt (OpenSSL)" openssl pkeyutl -encrypt -pubin \ | ||
| -keyform DER -inkey "$TMP/rsa.der" -in "$TMP/pt.bin" -out "$TMP/ct1.bin" \ | ||
| -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 \ | ||
| -pkeyopt rsa_mgf1_md:sha1 | ||
| run_test "RSA-OAEP-SHA1 decrypt" p11 --decrypt --mechanism RSA-PKCS-OAEP \ | ||
| --hash-algorithm SHA-1 --mgf MGF1-SHA1 --id 3032 \ | ||
| --input-file "$TMP/ct1.bin" --output-file "$TMP/dec1.bin" | ||
| run_test "RSA-OAEP-SHA1 plaintext matches" cmp "$TMP/pt.bin" "$TMP/dec1.bin" | ||
|
|
||
| echo "=== tpm2-pkcs11 results: $PASS passed, $FAIL failed ===" | ||
| [ "$FAIL" -eq 0 ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,6 +36,15 @@ | |
| #include <wolftpm/fwtpm/fwtpm_nv.h> | ||
| #include <string.h> | ||
|
|
||
| /* Clock resumes from its NV checkpoint and becomes safe one checkpoint | ||
| * interval later, unless the NV state kept it safe. */ | ||
| static void FwClockRestoreSafe(FWTPM_CTX* ctx) | ||
| { | ||
| ctx->clockUnsafeUntil = ctx->clockNvValue > | ||
| ~(UINT64)0 - FWTPM_CLOCK_UPDATE_MS ? ~(UINT64)0 : | ||
| ctx->clockNvValue + FWTPM_CLOCK_UPDATE_MS; | ||
| } | ||
|
|
||
| int FWTPM_Init(FWTPM_CTX* ctx) | ||
| { | ||
| int rc; | ||
|
|
@@ -134,6 +143,8 @@ int FWTPM_Init(FWTPM_CTX* ctx) | |
| /* Initialize NV storage - loads existing state or creates fresh seeds */ | ||
| #ifndef FWTPM_NO_NV | ||
| if (rc == 0) { | ||
| /* A compaction during the load cannot establish Clock safety. */ | ||
| ctx->clockUnsafeUntil = ~(UINT64)0; | ||
| rc = FWTPM_NV_Init(ctx); | ||
| } | ||
| #else | ||
|
|
@@ -152,6 +163,7 @@ int FWTPM_Init(FWTPM_CTX* ctx) | |
| if (rc == 0) { | ||
| ctx->pcrAllocatedBanks = FWTPM_PCR_ALLOC_DEFAULT; | ||
| ctx->endorsementProofVersion = 1; | ||
| ctx->clockSafe = 1; | ||
| } | ||
| #ifndef FWTPM_NO_DA | ||
| if (rc == 0) { | ||
|
|
@@ -163,6 +175,13 @@ int FWTPM_Init(FWTPM_CTX* ctx) | |
| #endif | ||
| #endif | ||
|
|
||
| /* The NV load keeps clockSafe only from a committed orderly marker. | ||
| * Fresh state has reported no Clock yet, so it is safe. */ | ||
| if (rc == TPM_RC_SUCCESS) { | ||
| ctx->clockNvValue = ctx->clockOffset; | ||
| FwClockRestoreSafe(ctx); | ||
| } | ||
|
|
||
| if (rc != 0) { | ||
| if (rngInit) { | ||
| wc_FreeRng(&ctx->rng); | ||
|
|
@@ -232,6 +251,45 @@ UINT64 FWTPM_Clock_GetMs(FWTPM_CTX* ctx) | |
| return now + ctx->clockOffset; | ||
| } | ||
|
|
||
| int FWTPM_Clock_PowerOn(FWTPM_CTX* ctx) | ||
| { | ||
| UINT64 halNow = 0; | ||
| if (ctx == NULL) { | ||
| return BAD_FUNC_ARG; | ||
| } | ||
| if (ctx->clockHal.get_ms != NULL) { | ||
| halNow = ctx->clockHal.get_ms(ctx->clockHal.ctx); | ||
| } | ||
| /* Powered-off time is not counted, whatever the HAL epoch. Unsigned | ||
| * wrap is intended, as in ClockSet. */ | ||
| ctx->clockOffset = ctx->clockNvValue - halNow; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No-NV power cycle reports a rolled-back Clock as safe In an Suggested fix: Handle no-NV power cycles so Clock cannot retain a true safety flag after returning below a value already reported, and add a no-NV regression test. |
||
| #ifndef FWTPM_NO_NV | ||
| ctx->clockSafe = ctx->nvOrderly && ctx->clockSafe; | ||
| #else | ||
| /* Without NV, Clock restarts from its boot value and can roll back. */ | ||
| ctx->clockSafe = 0; | ||
| #endif | ||
| FwClockRestoreSafe(ctx); | ||
| return TPM_RC_SUCCESS; | ||
| } | ||
|
|
||
| int FWTPM_Clock_Update(FWTPM_CTX* ctx) | ||
| { | ||
| if (ctx == NULL) return BAD_FUNC_ARG; | ||
| #if !defined(FWTPM_NO_CLOCK) && !defined(FWTPM_NO_NV) | ||
| if (ctx->wasStarted && ctx->powerOn) { | ||
| UINT64 now = FWTPM_Clock_GetMs(ctx); | ||
| if (now >= ctx->clockNvValue && | ||
| (now - ctx->clockNvValue >= | ||
| FWTPM_CLOCK_UPDATE_MS - FWTPM_CLOCK_POLL_MS || | ||
| (!ctx->clockSafe && now >= ctx->clockUnsafeUntil))) { | ||
| return FWTPM_NV_SaveClock(ctx); | ||
| } | ||
| } | ||
| #endif | ||
| return TPM_RC_SUCCESS; | ||
| } | ||
|
|
||
| #ifndef FWTPM_NO_PP | ||
| int FWTPM_PP_SetHAL(FWTPM_CTX* ctx, | ||
| int (*get_pp)(void* halCtx), void* halCtx) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.