blob: 61df7bad1ed003da325c4bcffb7ccce04c385895 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package hwsec
import (
"bytes"
"context"
"time"
"chromiumos/tast/common/hwsec"
"chromiumos/tast/errors"
hwsecremote "chromiumos/tast/remote/hwsec"
"chromiumos/tast/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: RetakeOwnershipLatePreparation,
Desc: "Verifies that late-startup attestation can still be prepared for enrollment after taking ownership and still capable of removing owner dependency",
Contacts: []string{"cylai@chromium.org", "cros-hwsec@google.com"},
SoftwareDeps: []string{"reboot", "tpm"},
Attr: []string{"group:hwsec_destructive_func"},
ServiceDeps: []string{"tast.cros.hwsec.AttestationDBusService"},
})
}
func RetakeOwnershipLatePreparation(ctx context.Context, s *testing.State) {
r := hwsecremote.NewCmdRunner(s.DUT())
helper, err := hwsecremote.NewFullHelper(r, s.DUT(), s.RPCHint())
if err != nil {
s.Fatal("Helper creation error: ", err)
}
tpmManager := helper.TPMManagerClient()
attestation := helper.AttestationClient()
s.Log("Start resetting TPM if needed")
if err := helper.EnsureTPMIsReset(ctx); err != nil {
s.Fatal("Failed to ensure resetting TPM: ", err)
}
s.Log("TPM is confirmed to be reset")
if result, err := attestation.IsPreparedForEnrollment(ctx); err != nil {
s.Fatal("Cannot check if enrollment preparation is reset: ", err)
} else if result {
s.Fatal("Enrollment preparation is not reset after clearing ownership")
}
dCtrl := helper.DaemonController()
dCtrl.Stop(ctx, hwsec.AttestationDaemon)
s.Log("Start taking ownership")
if err := helper.EnsureTPMIsReady(ctx, hwsec.DefaultTakingOwnershipTimeout); err != nil {
s.Fatal("Failed to ensure ownership: ", err)
}
s.Log("Ownership is taken")
if passwd, err := tpmManager.GetOwnerPassword(ctx); err != nil {
s.Fatal("Failed to get owner password: ", err)
} else if len(passwd) != hwsec.OwnerPasswordLength {
s.Fatalf("Unexpected owner password length: got %v; want %v", len(passwd), hwsec.OwnerPasswordLength)
}
s.Log("Start attestation service")
dCtrl.Start(ctx, hwsec.AttestationDaemon)
if err := helper.EnsureIsPreparedForEnrollment(ctx, hwsec.DefaultPreparationForEnrolmentTimeout); err != nil {
s.Fatal("Failed to prepare for enrollment: ", err)
}
s.Log("Attestation is prepared for enrollment")
s.Log("Clearing owner password")
lastTime, err := r.Run(ctx, "stat", "-c", "%y", "/var/lib/tpm_manager/local_tpm_data")
if err != nil {
s.Log("Error calling stat; the polling operation will check the tpm password in every loop")
}
if err := testing.Poll(ctx, func(ctx context.Context) error {
// This hacky logic watches the file modification of the persistent tpm status for both
// monolithic and distributed models.
// Ignores error here; if it's because file doesn't exist we assume the local data has changed.
if _, err := tpmManager.ClearOwnerPassword(ctx); err != nil {
return err
}
newTime, err := r.Run(ctx, "stat", "-c", "%y", "/var/lib/tpm_manager/local_tpm_data")
if err == nil && bytes.Equal(lastTime, newTime) {
return errors.New("no local data change")
}
lastTime = newTime
// For now, restarting cryptohome is necessary because we still use cryptohome binary.
if err := dCtrl.Restart(ctx, hwsec.CryptohomeDaemon); err != nil {
return err
}
if passwd, err := tpmManager.GetOwnerPassword(ctx); err != nil {
return err
} else if len(passwd) != 0 {
return errors.New("Still have password")
}
return nil
}, &testing.PollOptions{Interval: time.Second, Timeout: time.Minute}); err != nil {
s.Fatal("Failed to wait for owner password to be cleared: ", err)
}
}