blob: 52d8d3086917464831b8177c84730def915c24a7 [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package gscdevboard
import (
"context"
"time"
"github.com/google/go-tpm/tpm2"
"go.chromium.org/tast-tests/cros/common/firmware/ti50"
"go.chromium.org/tast-tests/cros/remote/bundles/cros/gscdevboard/utils"
"go.chromium.org/tast-tests/cros/remote/firmware/ti50/fixture"
"go.chromium.org/tast/core/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: GSCFWMP,
Desc: "Verifies various FWMP enforcement for GSC",
Timeout: 30 * time.Second,
Contacts: []string{
"gsc-sheriff@google.com", // CrOS GSC Developers
"jettrink@chromium.org", // Test Author
},
BugComponent: "b:715469", // ChromeOS > Platform > System > Hardware Security > HwSec GSC > Ti50
Attr: []string{"group:gsc", "gsc_dt_ab", "gsc_dt_shield", "gsc_h1_shield", "gsc_image_ti50", "gsc_nightly"},
Fixture: fixture.GSCOpenCCD,
})
}
// GSCFWMP verifies the FWMP can force write protect to be enabled
func GSCFWMP(ctx context.Context, s *testing.State) {
b := utils.NewDevboardHelper(s)
i := ti50.MustOpenCrOSImage(ctx, b, s)
defer i.Close(ctx)
tpm := b.ResetAndTpmStartup(ctx, i, ti50.CcdSuzyQ, ti50.FfClamshell)
err := tpm.TpmvCommitNvmem()
if err != nil {
s.Fatal("Failed to enable Nvmem writes: ", err)
}
// Undefine the space to ensure we are in a good state. Not a failure if doesn't work
attr := ti50.FwmpAttr()
tpm.NvUndefineSpace(attr)
verifyWpDisabledWithFwmp(ctx, s, b, i, tpm)
}
func verifyWpDisabledWithFwmp(ctx context.Context, s *testing.State, b utils.DevboardHelper, i *ti50.CrOSImage, tpm *utils.TpmHelper) {
s.Log("Verify WP works before FWMP unlock disable")
_, err := i.Command(ctx, "wp disable atboot")
if err != nil {
s.Fatal("Error communicating with ti50: ", err)
}
// Ensure write protect is disabled
if b.GpioGet(ctx, ti50.GpioTi50WriteProtectL) != true {
s.Fatal("WP signal not disable after `wp disable` console command")
}
attr := ti50.FwmpAttr()
nvName, err := tpm2.NVName(&attr)
if err != nil {
s.Fatal("Failed to get NV name: ", err)
}
nvHandle := tpm2.NamedHandle{
Handle: attr.NVIndex,
Name: *nvName,
}
s.Log("Write FWMP file with unlock disabled")
fwmpFile := utils.MakeFWMPFile(utils.FWMPDisableUnlock)
// Define space in NV storage and clean up afterwards
def := tpm2.NVDefineSpace{
AuthHandle: tpm2.TPMRHPlatform,
Auth: ti50.EmptyPassword(),
PublicInfo: tpm2.New2B(attr),
}
if _, err := def.Execute(tpm); err != nil {
s.Fatal("NVDefineSpace failed: ")
}
defer tpm.NvUndefineSpace(attr)
// Write the fwmp file data to new space.
write := tpm2.NVWrite{
AuthHandle: tpm2.TPMRHPlatform,
NVIndex: nvHandle,
Data: tpm2.TPM2BMaxNVBuffer{
Buffer: fwmpFile,
},
Offset: 0,
}
if _, err := write.Execute(tpm); err != nil {
s.Fatal("NVWrite failed: ", err)
}
// Ensure Write protect is disabled
if b.GpioGet(ctx, ti50.GpioTi50WriteProtectL) != false {
s.Fatal("WP signal not enabled after policy gets written to NVmem with FWMP unlocked disabled")
}
// Type the "wp disable" command again; this should have no affect because of FWMP
_, err = i.Command(ctx, "wp disable atboot")
if err != nil {
s.Fatal("Error communicating with ti50: ", err)
}
// Ensure Write protect is still enabled since wp command should have been blocked
if b.GpioGet(ctx, ti50.GpioTi50WriteProtectL) != false {
s.Fatal("WP signal not enabled after `wp disable` command, but should be blocked")
}
}