88 lines
3.1 KiB
Go
88 lines
3.1 KiB
Go
package platform
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// tpmDeviceGlob is a seam for tests. It reports the sysfs TPM device nodes
|
|
// the kernel has registered; an empty result means the platform exposes no
|
|
// TPM at all (no discrete chip, or firmware/BIOS has it disabled).
|
|
var tpmDeviceGlob = func() []string {
|
|
matches, _ := filepath.Glob("/sys/class/tpm/tpm*")
|
|
return matches
|
|
}
|
|
|
|
var tpmReadFile = os.ReadFile
|
|
|
|
// TPMPresent reports whether sysfs identifies a registered device as TPM 2.x.
|
|
// The validation pack uses tpm2-tools, so a TPM 1.2 device is not sufficient.
|
|
func (s *System) TPMPresent() bool {
|
|
for _, device := range tpmDeviceGlob() {
|
|
version, err := tpmReadFile(filepath.Join(device, "tpm_version_major"))
|
|
if err == nil && strings.TrimSpace(string(version)) == "2" {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// RunTPMValidationPack verifies TPM 2.0 communication using read-only
|
|
// commands. It deliberately excludes SelfTest, provisioning, NV writes, PCR
|
|
// changes, key creation, and ownership operations.
|
|
//
|
|
// When the platform exposes no TPM device at all, the pack does not run the
|
|
// tpm2_* tools: without a TCTI device they only ever emit a wall of
|
|
// "Failed to open ... /dev/tpmrm0" errors that read as a hard failure when
|
|
// the real situation is "this machine has no TPM". Instead it writes an
|
|
// UNSUPPORTED summary and returns, the same way the storage pack handles a
|
|
// host with no drives.
|
|
func (s *System) RunTPMValidationPack(ctx context.Context, baseDir string, logFunc func(string)) (string, error) {
|
|
if !s.TPMPresent() {
|
|
return writeTPMUnsupportedRun(baseDir, logFunc)
|
|
}
|
|
return runAcceptancePackCtx(ctx, baseDir, "tpm", tpmValidationJobs(), logFunc)
|
|
}
|
|
|
|
func writeTPMUnsupportedRun(baseDir string, logFunc func(string)) (string, error) {
|
|
if strings.TrimSpace(baseDir) == "" {
|
|
baseDir = "/var/log/bee-sat"
|
|
}
|
|
now := time.Now().UTC()
|
|
runDir := filepath.Join(baseDir, "tpm-"+now.Format("20060102-150405"))
|
|
if err := os.MkdirAll(runDir, 0755); err != nil {
|
|
return "", err
|
|
}
|
|
if logFunc != nil {
|
|
logFunc("no TPM 2.x device reported by sysfs; skipping read-only TPM checks")
|
|
}
|
|
|
|
var summary strings.Builder
|
|
fmt.Fprintf(&summary, "run_at_utc=%s\n", now.Format(time.RFC3339))
|
|
summary.WriteString("tpm_present=false\n")
|
|
summary.WriteString("skip_reason=no TPM 2.x device reported by sysfs; tpm2-tools are not applicable\n")
|
|
summary.WriteString("tpm_check_status=UNSUPPORTED\n")
|
|
summary.WriteString("overall_status=UNSUPPORTED\n")
|
|
summary.WriteString("job_ok=0\n")
|
|
summary.WriteString("job_failed=0\n")
|
|
summary.WriteString("job_unsupported=1\n")
|
|
summary.WriteString("job_informational_failed=0\n")
|
|
if err := os.WriteFile(filepath.Join(runDir, "summary.txt"), []byte(summary.String()), 0644); err != nil {
|
|
return "", err
|
|
}
|
|
return runDir, nil
|
|
}
|
|
|
|
func tpmValidationJobs() []satJob {
|
|
return []satJob{
|
|
{name: "01-properties-fixed.log", cmd: []string{"tpm2_getcap", "properties-fixed"}},
|
|
{name: "02-pcr-banks.log", cmd: []string{"tpm2_getcap", "pcrs"}},
|
|
{name: "03-pcr-values.log", cmd: []string{"tpm2_pcrread"}},
|
|
{name: "04-test-result.log", cmd: []string{"tpm2_gettestresult"}},
|
|
}
|
|
}
|