Skip to content

Commit

Permalink
tpmmgr/tpm : move tests from tpmmgr to tpm
Browse files Browse the repository at this point in the history
Adds tpm_test.go and moves tests that are local to tpm from tpmmgr to it.

Signed-off-by: Shahriyar Jalayeri <[email protected]>
  • Loading branch information
shjala authored and rouming committed Sep 5, 2023
1 parent a0413e3 commit 28f38e7
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 168 deletions.
144 changes: 0 additions & 144 deletions pkg/pillar/cmd/tpmmgr/tpmmgr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,15 @@
package tpmmgr

import (
"bytes"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"os"
"reflect"
"strings"
"testing"
"time"

"github.com/google/go-tpm/tpm2"
"github.com/google/go-tpm/tpmutil"
etpm "github.com/lf-edge/eve/pkg/pillar/evetpm"
fileutils "github.com/lf-edge/eve/pkg/pillar/utils/file"
)

const ecdhCertPem = `
Expand Down Expand Up @@ -208,140 +201,3 @@ func TestVerifyEdgeNodeCerts(t *testing.T) {
return
}
}

func TestSealUnseal(t *testing.T) {
_, err := os.Stat(etpm.TpmDevicePath)
if err != nil {
t.Skip("TPM is not available, skipping the test.")
}

dataToSeal := []byte("secret")
if err := etpm.SealDiskKey(dataToSeal, etpm.DiskKeySealingPCRs); err != nil {
t.Errorf("Seal operation failed with err: %v", err)
return
}
unsealedData, err := etpm.UnsealDiskKey(etpm.DiskKeySealingPCRs)
if err != nil {
t.Errorf("Unseal operation failed with err: %v", err)
return
}
if !reflect.DeepEqual(dataToSeal, unsealedData) {
t.Errorf("Seal/Unseal operation failed, want %v, but got %v", dataToSeal, unsealedData)
}
}

func TestSealUnsealMismatchReport(t *testing.T) {
_, err := os.Stat(etpm.TpmDevicePath)
if err != nil {
t.Skip("TPM is not available, skipping the test.")
}

rw, err := tpm2.OpenTPM(etpm.TpmDevicePath)
if err != nil {
t.Errorf("OpenTPM failed with err: %v", err)
return
}
defer rw.Close()

dataToSeal := []byte("secret")
if err := etpm.SealDiskKey(dataToSeal, etpm.DiskKeySealingPCRs); err != nil {
t.Errorf("Seal operation failed with err: %v", err)
return
}

pcrIndexes := [3]int{1, 7, 8}
pcrValue := bytes.Repeat([]byte{0xF}, sha256.Size)
for _, pcr := range pcrIndexes {
if err = tpm2.PCRExtend(rw, tpmutil.Handle(pcr), tpm2.AlgSHA256, pcrValue, ""); err != nil {
t.Errorf("Failed to extend PCR %d: %s", pcr, err)
return
}
}

_, err = etpm.UnsealDiskKey(etpm.DiskKeySealingPCRs)
if err == nil {
t.Errorf("Expected error from UnsealDiskKey, got nil")
return
}

if !strings.Contains(err.Error(), "[1 7 8]") {
t.Errorf("UnsealDiskKey expected to report mismatching PCR indexes, got : %v", err)
return
}
}

func TestSealUnsealTpmEventLogCollect(t *testing.T) {
_, err := os.Stat(etpm.TpmDevicePath)
if err != nil {
t.Skip("TPM is not available, skipping the test.")
}

rw, err := tpm2.OpenTPM(etpm.TpmDevicePath)
if err != nil {
t.Errorf("OpenTPM failed with err: %v", err)
return
}
defer rw.Close()

// this should write the save the first event log
dataToSeal := []byte("secret")
if err := etpm.SealDiskKey(dataToSeal, etpm.DiskKeySealingPCRs); err != nil {
t.Errorf("Seal operation failed with err: %v", err)
return
}

// this won't write to event log, but still triggers saving it on unseal.
pcrValue := bytes.Repeat([]byte{0xF}, sha256.Size)
if err = tpm2.PCRExtend(rw, tpmutil.Handle(1), tpm2.AlgSHA256, pcrValue, ""); err != nil {
t.Errorf("Failed to extend PCR[1]: %v", err)
return
}

// this should fail and result in saving the second tpm event log
_, err = etpm.UnsealDiskKey(etpm.DiskKeySealingPCRs)
if err == nil {
t.Errorf("Expected error from UnsealDiskKey, got nil")
return
}

// just check for tpm0
sealSuccess := fmt.Sprintf(etpm.TpmEvtLogSavePattern, etpm.MeasurementLogSealSuccess, 0)
sealFail := fmt.Sprintf(etpm.TpmEvtLogSavePattern, etpm.MeasurementLogUnsealFail, 0)
if !fileutils.FileExists(nil, sealSuccess) {
t.Errorf("TPM event log \"%s\" not found, Expected to be saved", sealSuccess)
return
}
if !fileutils.FileExists(nil, sealFail) {
t.Errorf("TPM event log \"%s\" not found, Expected to be saved", sealFail)
return
}

// this should trigger collecting previous tpm event logs
if err := etpm.SealDiskKey(dataToSeal, etpm.DiskKeySealingPCRs); err != nil {
t.Errorf("Seal operation failed with err: %v", err)
return
}

// current event log should exist
if !fileutils.FileExists(nil, sealSuccess) {
t.Errorf("TPM event log \"%s\" not found, Expected to be saved", sealSuccess)
return
}
// this shouldn't exist because SealDiskKey will do a clean up
if fileutils.FileExists(nil, sealFail) {
t.Errorf("TPM event log \"%s\" found, Expected to not exist", sealFail)
return
}

// collected event logs both should exist
prevSealSuccess := fmt.Sprintf(etpm.TpmEvtLogCollectPattern, sealSuccess)
prevSealFail := fmt.Sprintf(etpm.TpmEvtLogCollectPattern, sealFail)
if !fileutils.FileExists(nil, prevSealSuccess) {
t.Errorf("TPM event log \"%s\" not found, Expected to be collected", prevSealSuccess)
return
}
if !fileutils.FileExists(nil, prevSealFail) {
t.Errorf("TPM event log \"%s\" not found, Expected to be collected", prevSealFail)
return
}
}
49 changes: 25 additions & 24 deletions pkg/pillar/evetpm/tpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,24 +75,17 @@ const (
EmptyPassword = ""
vaultKeyLength = 32 //Bytes

// TpmSavedDiskSealingPcrs is the file that holds a copy of PCR values
// savedSealingPcrsFile is the file that holds a copy of PCR values
// at the time of generating and sealing the disk key into the TPM.
TpmSavedDiskSealingPcrs = types.PersistStatusDir + "/sealingpcrs"
savedSealingPcrsFile = types.PersistStatusDir + "/sealingpcrs"

// MeasurementLogSealSuccess is files that holds a copy of event log at the time
// measurementLogSealSuccess is files that holds a copy of event log at the time
// of generating/sealing the disk key into the TPM.
MeasurementLogSealSuccess = types.PersistStatusDir + "/tpm_measurement_seal_success"
measurementLogSealSuccess = types.PersistStatusDir + "/tpm_measurement_seal_success"

// MeasurementLogUnsealFail is files that holds a copy of event log at the time EVE
// measurementLogUnsealFail is files that holds a copy of event log at the time EVE
// fails to unseal the vault key from TPM.
MeasurementLogUnsealFail = types.PersistStatusDir + "/tpm_measurement_unseal_fail"

// TpmEvtLogSavePattern contains the pattern used to save event log files,
// considering the case when multiple tpm devices are present.
TpmEvtLogSavePattern = "%s-tpm%d"

// TpmEvtLogCollectPattern contains the pattern used to collect event log files.
TpmEvtLogCollectPattern = "%s-backup"
measurementLogUnsealFail = types.PersistStatusDir + "/tpm_measurement_unseal_fail"

// measurementLogFile is a kernel exposed variable that contains the
// TPM measurements and events log.
Expand Down Expand Up @@ -653,7 +646,7 @@ func SealDiskKey(key []byte, pcrSel tpm2.PCRSelection) error {
}

// save a snapshot of current PCR values
if err := saveDiskKeySealingPCRs(TpmSavedDiskSealingPcrs); err != nil {
if err := saveDiskKeySealingPCRs(savedSealingPcrsFile); err != nil {
return fmt.Errorf("saving snapshot of sealing PCRs failed: %w", err)
}

Expand All @@ -673,7 +666,7 @@ func SealDiskKey(key []byte, pcrSel tpm2.PCRSelection) error {
}

// save a copy of the current measurement log
if err := copyMeasurementLog(MeasurementLogSealSuccess); err != nil {
if err := copyMeasurementLog(measurementLogSealSuccess); err != nil {
return fmt.Errorf("copying current TPM measurement log failed: %w", err)
}

Expand Down Expand Up @@ -735,14 +728,14 @@ func UnsealDiskKey(pcrSel tpm2.PCRSelection) ([]byte, error) {
// We get here mostly because of RCPolicyFail error, so first try to save
// a copy of TPM measurement log, it comes handy for diagnosing the issue.
evtLogStat := "copied (failed unseal) TPM measurement log"
if errEvtLog := copyMeasurementLog(MeasurementLogUnsealFail); errEvtLog != nil {
if errEvtLog := copyMeasurementLog(measurementLogUnsealFail); errEvtLog != nil {
// just report the failure, still give findMismatchingPCRs a chance so
// we can at least have some partial information about why unseal failed.
evtLogStat = fmt.Sprintf("copying (failed unseal) TPM measurement log failed: %v", errEvtLog)
}

// try to find out the mismatching PCR index
mismatch, errPcrMiss := findMismatchingPCRs(TpmSavedDiskSealingPcrs)
mismatch, errPcrMiss := findMismatchingPCRs(savedSealingPcrsFile)
if errPcrMiss != nil {
return nil, fmt.Errorf("UnsealWithSession failed: %w, %s, finding mismatching PCR failed: %v", err, evtLogStat, errPcrMiss)
}
Expand Down Expand Up @@ -857,6 +850,14 @@ func pcrBankSHA256EnabledHelper() bool {
return err == nil
}

func getLogCopyPath(destination string, tpmIndex int) string {
return fmt.Sprintf("%s-tpm%d", destination, tpmIndex)
}

func getLogBackupPath(destination string) string {
return fmt.Sprintf("%s-backup", destination)
}

func getMappedTpmsPath() ([]string, error) {
paths, err := filepath.Glob(syfsTpmDir)
if err != nil {
Expand Down Expand Up @@ -902,11 +903,11 @@ func backupCopiedMeasurementLogs() error {

leftToBackup := counted
for i := 0; i < counted; i++ {
sealSuccessPath := fmt.Sprintf(TpmEvtLogSavePattern, MeasurementLogSealSuccess, i)
unsealFailPath := fmt.Sprintf(TpmEvtLogSavePattern, MeasurementLogUnsealFail, i)
sealSuccessPath := getLogCopyPath(measurementLogSealSuccess, i)
unsealFailPath := getLogCopyPath(measurementLogUnsealFail, i)
if fileutils.FileExists(nil, sealSuccessPath) && fileutils.FileExists(nil, unsealFailPath) {
sealSuccessBackupPath := fmt.Sprintf(TpmEvtLogCollectPattern, sealSuccessPath)
unsealFailBackupPath := fmt.Sprintf(TpmEvtLogCollectPattern, unsealFailPath)
sealSuccessBackupPath := getLogBackupPath(sealSuccessPath)
unsealFailBackupPath := getLogBackupPath(unsealFailPath)
if err := os.Rename(sealSuccessPath, sealSuccessBackupPath); err != nil {
fmt.Fprintf(os.Stderr, "failed to backup tpm%d \"seal success\" previously copied measurement log: %v", i, err)
continue
Expand Down Expand Up @@ -935,8 +936,8 @@ func removeCopiedMeasurementLogs() error {
}

for i := 0; i < counted; i++ {
sealSuccessPath := fmt.Sprintf(TpmEvtLogSavePattern, MeasurementLogSealSuccess, i)
unsealFailPath := fmt.Sprintf(TpmEvtLogSavePattern, MeasurementLogUnsealFail, i)
sealSuccessPath := getLogCopyPath(measurementLogSealSuccess, i)
unsealFailPath := getLogCopyPath(measurementLogUnsealFail, i)
_ = os.Remove(sealSuccessPath)
_ = os.Remove(unsealFailPath)
}
Expand All @@ -958,7 +959,7 @@ func copyMeasurementLog(dstPath string) error {
continue
}

copyPath := fmt.Sprintf(TpmEvtLogSavePattern, dstPath, i)
copyPath := getLogCopyPath(dstPath, i)
err = fileutils.WriteRename(copyPath, measurementLogContent)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to copy stored measurement log file: %v", err)
Expand Down
Loading

0 comments on commit 28f38e7

Please sign in to comment.