diff --git a/go.mod b/go.mod
index c5774ef5..9cb64703 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
github.com/canonical/go-efilib v1.4.1
github.com/canonical/go-sp800.108-kdf v0.0.0-20210315104021-ead800bbf9a0
github.com/canonical/go-sp800.90a-drbg v0.0.0-20210314144037-6eeb1040d6c3
- github.com/canonical/go-tpm2 v1.7.6
+ github.com/canonical/go-tpm2 v1.8.1-0.20250106220815-bd8d7cc9ba17
github.com/canonical/tcglog-parser v0.0.0-20240924110432-d15eaf652981
github.com/snapcore/snapd v0.0.0-20220714152900-4a1f4c93fc85
golang.org/x/crypto v0.21.0
@@ -19,6 +19,7 @@ require (
)
require (
+ github.com/canonical/go-kbkdf v0.0.0-20250104172618-3b1308f9acf9 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/kr/pretty v0.2.2-0.20200810074440-814ac30b4b18 // indirect
github.com/kr/text v0.1.0 // indirect
diff --git a/go.sum b/go.sum
index 5deb1484..22d2de59 100644
--- a/go.sum
+++ b/go.sum
@@ -3,14 +3,16 @@ github.com/canonical/cpuid v0.0.0-20220614022739-219e067757cb/go.mod h1:6j8Sw3dw
github.com/canonical/go-efilib v0.0.0-20210909101908-41435fa545d4/go.mod h1:9Sr9kd7IhQPYqaU5nut8Ky97/CtlhHDzQncQnrULgDM=
github.com/canonical/go-efilib v1.4.1 h1:/VMNCypz+iVmnNuMcsm7WvmDMI1ObkEP2W1h8Ls7OyM=
github.com/canonical/go-efilib v1.4.1/go.mod h1:n0Ttsy1JuHAvqaFbZBs6PAzoiiJdfkHsAmDOEbexYEQ=
+github.com/canonical/go-kbkdf v0.0.0-20250104172618-3b1308f9acf9 h1:Twk1ZSTWRClfGShP16ePf2JIiayqWS4ix1rkAR6baag=
+github.com/canonical/go-kbkdf v0.0.0-20250104172618-3b1308f9acf9/go.mod h1:IneQ5/yQcfPXrGekEXpR6yeea55ZD24N5+kHzeDseOM=
github.com/canonical/go-sp800.108-kdf v0.0.0-20210314145419-a3359f2d21b9/go.mod h1:Zrs3YjJr+w51u0R/dyLh/oWt/EcBVdLPCVFYC4daW5s=
github.com/canonical/go-sp800.108-kdf v0.0.0-20210315104021-ead800bbf9a0 h1:ZE2XMRFHcwlib3uU9is37+pKkkMloVoEPWmgQ6GK1yo=
github.com/canonical/go-sp800.108-kdf v0.0.0-20210315104021-ead800bbf9a0/go.mod h1:Zrs3YjJr+w51u0R/dyLh/oWt/EcBVdLPCVFYC4daW5s=
github.com/canonical/go-sp800.90a-drbg v0.0.0-20210314144037-6eeb1040d6c3 h1:oe6fCvaEpkhyW3qAicT0TnGtyht/UrgvOwMcEgLb7Aw=
github.com/canonical/go-sp800.90a-drbg v0.0.0-20210314144037-6eeb1040d6c3/go.mod h1:qdP0gaj0QtgX2RUZhnlVrceJ+Qln8aSlDyJwelLLFeM=
github.com/canonical/go-tpm2 v0.0.0-20210827151749-f80ff5afff61/go.mod h1:vG41hdbBjV4+/fkubTT1ENBBqSkLwLr7mCeW9Y6kpZY=
-github.com/canonical/go-tpm2 v1.7.6 h1:9k9OAEEp9xKp4h2WJwfTUNivblJi4L5Wjx7Q/LkSTSQ=
-github.com/canonical/go-tpm2 v1.7.6/go.mod h1:Dz0PQRmoYrmk/4BLILjRA+SFzuqEo1etAvYeAJiMhYU=
+github.com/canonical/go-tpm2 v1.8.1-0.20250106220815-bd8d7cc9ba17 h1:bzX4uvym3OoyKAQd2fTUOP4tAuHbQktwsezk6KTXAgc=
+github.com/canonical/go-tpm2 v1.8.1-0.20250106220815-bd8d7cc9ba17/go.mod h1:zK+qESVwu78XyX+NPhiBdN+zwPPDoKk4rYlQ7VUsRp4=
github.com/canonical/tcglog-parser v0.0.0-20210824131805-69fa1e9f0ad2/go.mod h1:QoW2apR2tBl6T/4czdND/EHjL1Ia9cCmQnIj9Xe0Kt8=
github.com/canonical/tcglog-parser v0.0.0-20240924110432-d15eaf652981 h1:vrUzSfbhl8mzdXPzjxq4jXZPCCNLv18jy6S7aVTS2tI=
github.com/canonical/tcglog-parser v0.0.0-20240924110432-d15eaf652981/go.mod h1:ywdPBqUGkuuiitPpVWCfilf2/gq+frhq4CNiNs9KyHU=
diff --git a/internal/tpm2_device/device.go b/internal/tpm2_device/device.go
new file mode 100644
index 00000000..f0b33ffd
--- /dev/null
+++ b/internal/tpm2_device/device.go
@@ -0,0 +1,97 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2024 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tpm2_device
+
+import (
+ "errors"
+
+ "github.com/canonical/go-tpm2"
+ "github.com/canonical/go-tpm2/ppi"
+)
+
+// DeviceMode describes the mode to select the default device.
+type DeviceMode int
+
+const (
+ // DeviceModeDirect requests the most direct TPM2 device, without
+ // the use of a resource manager. These devices cannot be opened more
+ // than once and don't permit the TPM to be shared.
+ DeviceModeDirect DeviceMode = iota
+
+ // DeviceModeResourceManaged requests a resource managed TPM2 device.
+ // These devices can be opened more than once and sharedi, relying on
+ // the resource manager to handle context switching between users
+ // (although they can't be shared with a direct device).
+ DeviceModeResourceManaged
+
+ // DeviceModeTryResourceManaged is like DeviceModeResourceManaged except
+ // it will return a direct device if a resource managed device is not
+ // available. Some older linux kernels do not support an in-kernel resource
+ // manager.
+ DeviceModeTryResourceManaged
+)
+
+var (
+ // ErrNoTPM2Device indicates that no TPM2 device is available.
+ ErrNoTPM2Device = errors.New("no TPM2 device is available")
+
+ // ErrNoResourceManagedTPM2Device indicates that there is no resource
+ // managed TPM2 device option available.
+ ErrNoResourceManagedTPM2Device = errors.New("no resource managed TPM2 device available")
+
+ // ErrNoPPI indicates that no physical presence interface is available.
+ ErrNoPPI = errors.New("no physical presence interface available")
+)
+
+type tpmDevice struct {
+ tpm2.TPMDevice
+
+ mode DeviceMode
+
+ ppi ppi.PPI
+ ppiErr error
+}
+
+func (d *tpmDevice) Mode() DeviceMode {
+ return d.mode
+}
+
+func (d *tpmDevice) PPI() (ppi.PPI, error) {
+ if d.ppiErr != nil {
+ return nil, d.ppiErr
+ }
+ if d.ppi == nil {
+ return nil, ErrNoPPI
+ }
+ return d.ppi, nil
+}
+
+// TPMDevice corresponds to a [tpm2.TPMDevice] with some extra features.
+type TPMDevice interface {
+ tpm2.TPMDevice
+ Mode() DeviceMode // either DeviceModeDirect or DeviceModeResourceManaged
+ PPI() (ppi.PPI, error) // provide access to the physical presence interface
+}
+
+// DefaultDevice returns the default TPM device. The specified mode controls what kind
+// of device to return, if available.
+var DefaultDevice = func(DeviceMode) (TPMDevice, error) {
+ return nil, ErrNoTPM2Device
+}
diff --git a/internal/tpm2_device/device_linux.go b/internal/tpm2_device/device_linux.go
new file mode 100644
index 00000000..39785b93
--- /dev/null
+++ b/internal/tpm2_device/device_linux.go
@@ -0,0 +1,92 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2024 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tpm2_device
+
+import (
+ "errors"
+
+ "github.com/canonical/go-tpm2/linux"
+)
+
+var (
+ linuxDefaultTPM2Device = linux.DefaultTPM2Device
+ linuxRawDeviceResourceManagedDevice = (*linux.RawDevice).ResourceManagedDevice
+ linuxRawDevicePhysicalPresenceInterface = (*linux.RawDevice).PhysicalPresenceInterface
+ linuxRMDeviceRawDevice = (*linux.RMDevice).RawDevice
+)
+
+func newTpmDeviceDirect(dev *linux.RawDevice) TPMDevice {
+ ppi, err := linuxRawDevicePhysicalPresenceInterface(dev)
+ if errors.Is(err, linux.ErrNoPhysicalPresenceInterface) {
+ err = nil
+ }
+ return &tpmDevice{
+ TPMDevice: dev,
+ mode: DeviceModeDirect,
+ ppi: ppi,
+ ppiErr: err,
+ }
+}
+
+func newTpmDeviceRM(dev *linux.RMDevice) TPMDevice {
+ ppi, err := linuxRawDevicePhysicalPresenceInterface(linuxRMDeviceRawDevice(dev))
+ if errors.Is(err, linux.ErrNoPhysicalPresenceInterface) {
+ err = nil
+ }
+ return &tpmDevice{
+ TPMDevice: dev,
+ mode: DeviceModeResourceManaged,
+ ppi: ppi,
+ ppiErr: err,
+ }
+}
+
+func init() {
+ DefaultDevice = func(mode DeviceMode) (TPMDevice, error) {
+ rawDev, err := linuxDefaultTPM2Device()
+ switch {
+ case errors.Is(err, linux.ErrDefaultNotTPM2Device) || errors.Is(err, linux.ErrNoTPMDevices):
+ // Either there are no TPM devices or the default device is a TPM1.2 device
+ return nil, ErrNoTPM2Device
+ case err != nil:
+ return nil, err
+ }
+
+ if mode == DeviceModeDirect {
+ // Return the direct device
+ return newTpmDeviceDirect(rawDev), nil
+ }
+
+ rmDev, err := linuxRawDeviceResourceManagedDevice(rawDev)
+ switch {
+ case errors.Is(err, linux.ErrNoResourceManagedDevice) && mode == DeviceModeTryResourceManaged:
+ // No in-kernel resource manager, but the mode allows us to return the direct device
+ return newTpmDeviceDirect(rawDev), nil
+ case errors.Is(err, linux.ErrNoResourceManagedDevice):
+ // No in-kernel resource manager, return an error
+ return nil, ErrNoResourceManagedTPM2Device
+ case err != nil:
+ return nil, err
+ }
+
+ // Return the resource managed device
+ return newTpmDeviceRM(rmDev), nil
+ }
+}
diff --git a/internal/tpm2_device/device_linux_test.go b/internal/tpm2_device/device_linux_test.go
new file mode 100644
index 00000000..5a3f4c1b
--- /dev/null
+++ b/internal/tpm2_device/device_linux_test.go
@@ -0,0 +1,345 @@
+//go:build linux
+
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2024 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tpm2_device_test
+
+import (
+ "errors"
+
+ "github.com/canonical/go-tpm2/linux"
+ "github.com/canonical/go-tpm2/ppi"
+ . "github.com/snapcore/secboot/internal/tpm2_device"
+ . "gopkg.in/check.v1"
+)
+
+type deviceLinuxSuite struct{}
+
+var _ = Suite(&deviceLinuxSuite{})
+
+func (s *deviceLinuxSuite) TestDefaultDeviceDefaultNotTPM2Device(c *C) {
+ restore := MockLinuxDefaultTPM2Device(func() (*linux.RawDevice, error) {
+ return nil, linux.ErrDefaultNotTPM2Device
+ })
+ defer restore()
+
+ _, err := DefaultDevice(DeviceModeDirect)
+ c.Check(err, Equals, ErrNoTPM2Device)
+}
+
+func (s *deviceLinuxSuite) TestDefaultDeviceDefaultNoTPMDevices(c *C) {
+ restore := MockLinuxDefaultTPM2Device(func() (*linux.RawDevice, error) {
+ return nil, linux.ErrNoTPMDevices
+ })
+ defer restore()
+
+ _, err := DefaultDevice(DeviceModeDirect)
+ c.Check(err, Equals, ErrNoTPM2Device)
+}
+
+func (s *deviceLinuxSuite) TestDefaultDeviceDefaultOtherError(c *C) {
+ restore := MockLinuxDefaultTPM2Device(func() (*linux.RawDevice, error) {
+ return nil, errors.New("some error")
+ })
+ defer restore()
+
+ _, err := DefaultDevice(DeviceModeDirect)
+ c.Check(err, ErrorMatches, `some error`)
+}
+
+func (s *deviceLinuxSuite) TestDefaultDeviceDirect(c *C) {
+ expectedRaw := new(linux.RawDevice)
+ expectedPPI := new(mockPPI)
+
+ restore := MockLinuxDefaultTPM2Device(func() (*linux.RawDevice, error) {
+ return expectedRaw, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDevicePhysicalPresenceInterface(func(raw *linux.RawDevice) (ppi.PPI, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return expectedPPI, nil
+ })
+ defer restore()
+
+ dev, err := DefaultDevice(DeviceModeDirect)
+ c.Check(err, IsNil)
+ c.Check(dev, DeepEquals, NewTPMDevice(expectedRaw, DeviceModeDirect, expectedPPI, nil))
+}
+
+func (s *deviceLinuxSuite) TestDefaultDeviceDirectNoPPI(c *C) {
+ expectedRaw := new(linux.RawDevice)
+
+ restore := MockLinuxDefaultTPM2Device(func() (*linux.RawDevice, error) {
+ return expectedRaw, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDevicePhysicalPresenceInterface(func(raw *linux.RawDevice) (ppi.PPI, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return nil, linux.ErrNoPhysicalPresenceInterface
+ })
+ defer restore()
+
+ dev, err := DefaultDevice(DeviceModeDirect)
+ c.Check(err, IsNil)
+ c.Check(dev, DeepEquals, NewTPMDevice(expectedRaw, DeviceModeDirect, nil, nil))
+}
+
+func (s *deviceLinuxSuite) TestDefaultDeviceDirectPPIError(c *C) {
+ expectedRaw := new(linux.RawDevice)
+
+ restore := MockLinuxDefaultTPM2Device(func() (*linux.RawDevice, error) {
+ return expectedRaw, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDevicePhysicalPresenceInterface(func(raw *linux.RawDevice) (ppi.PPI, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return nil, errors.New("some error")
+ })
+ defer restore()
+
+ dev, err := DefaultDevice(DeviceModeDirect)
+ c.Check(err, IsNil)
+ c.Check(dev, DeepEquals, NewTPMDevice(expectedRaw, DeviceModeDirect, nil, errors.New("some error")))
+}
+
+func (s *deviceLinuxSuite) TestDefaultDeviceTryResourceManaged(c *C) {
+ expectedRaw := new(linux.RawDevice)
+ expectedPPI := new(mockPPI)
+ expectedRM := new(linux.RMDevice)
+
+ restore := MockLinuxDefaultTPM2Device(func() (*linux.RawDevice, error) {
+ return expectedRaw, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDevicePhysicalPresenceInterface(func(raw *linux.RawDevice) (ppi.PPI, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return expectedPPI, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDeviceResourceManagedDevice(func(raw *linux.RawDevice) (*linux.RMDevice, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return expectedRM, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRMDeviceRawDevice(func(rm *linux.RMDevice) *linux.RawDevice {
+ c.Check(rm, Equals, expectedRM)
+ return expectedRaw
+ })
+ defer restore()
+
+ dev, err := DefaultDevice(DeviceModeTryResourceManaged)
+ c.Check(err, IsNil)
+ c.Check(dev, DeepEquals, NewTPMDevice(expectedRM, DeviceModeResourceManaged, expectedPPI, nil))
+}
+
+func (s *deviceLinuxSuite) TestDefaultDeviceTryResourceManagedNoPPI(c *C) {
+ expectedRaw := new(linux.RawDevice)
+ expectedRM := new(linux.RMDevice)
+
+ restore := MockLinuxDefaultTPM2Device(func() (*linux.RawDevice, error) {
+ return expectedRaw, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDevicePhysicalPresenceInterface(func(raw *linux.RawDevice) (ppi.PPI, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return nil, linux.ErrNoPhysicalPresenceInterface
+ })
+ defer restore()
+
+ restore = MockLinuxRawDeviceResourceManagedDevice(func(raw *linux.RawDevice) (*linux.RMDevice, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return expectedRM, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRMDeviceRawDevice(func(rm *linux.RMDevice) *linux.RawDevice {
+ c.Check(rm, Equals, expectedRM)
+ return expectedRaw
+ })
+ defer restore()
+
+ dev, err := DefaultDevice(DeviceModeTryResourceManaged)
+ c.Check(err, IsNil)
+ c.Check(dev, DeepEquals, NewTPMDevice(expectedRM, DeviceModeResourceManaged, nil, nil))
+}
+
+func (s *deviceLinuxSuite) TestDefaultDeviceTryResourceManagedPPIErr(c *C) {
+ expectedRaw := new(linux.RawDevice)
+ expectedRM := new(linux.RMDevice)
+
+ restore := MockLinuxDefaultTPM2Device(func() (*linux.RawDevice, error) {
+ return expectedRaw, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDevicePhysicalPresenceInterface(func(raw *linux.RawDevice) (ppi.PPI, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return nil, errors.New("some error")
+ })
+ defer restore()
+
+ restore = MockLinuxRawDeviceResourceManagedDevice(func(raw *linux.RawDevice) (*linux.RMDevice, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return expectedRM, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRMDeviceRawDevice(func(rm *linux.RMDevice) *linux.RawDevice {
+ c.Check(rm, Equals, expectedRM)
+ return expectedRaw
+ })
+ defer restore()
+
+ dev, err := DefaultDevice(DeviceModeTryResourceManaged)
+ c.Check(err, IsNil)
+ c.Check(dev, DeepEquals, NewTPMDevice(expectedRM, DeviceModeResourceManaged, nil, errors.New("some error")))
+}
+
+func (s *deviceLinuxSuite) TestDefaultDeviceTryResourceManagedNoRM(c *C) {
+ expectedRaw := new(linux.RawDevice)
+ expectedPPI := new(mockPPI)
+
+ restore := MockLinuxDefaultTPM2Device(func() (*linux.RawDevice, error) {
+ return expectedRaw, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDevicePhysicalPresenceInterface(func(raw *linux.RawDevice) (ppi.PPI, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return expectedPPI, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDeviceResourceManagedDevice(func(raw *linux.RawDevice) (*linux.RMDevice, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return nil, linux.ErrNoResourceManagedDevice
+ })
+ defer restore()
+
+ restore = MockLinuxRMDeviceRawDevice(func(rm *linux.RMDevice) *linux.RawDevice {
+ c.Errorf("unexpected call to linux.RMDevice.RawDevice()")
+ return nil
+ })
+ defer restore()
+
+ dev, err := DefaultDevice(DeviceModeTryResourceManaged)
+ c.Check(err, IsNil)
+ c.Check(dev, DeepEquals, NewTPMDevice(expectedRaw, DeviceModeDirect, expectedPPI, nil))
+}
+
+func (s *deviceLinuxSuite) TestDefaultDeviceTryResourceManagedErr(c *C) {
+ expectedRaw := new(linux.RawDevice)
+
+ restore := MockLinuxDefaultTPM2Device(func() (*linux.RawDevice, error) {
+ return expectedRaw, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDevicePhysicalPresenceInterface(func(raw *linux.RawDevice) (ppi.PPI, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return nil, linux.ErrNoPhysicalPresenceInterface
+ })
+ defer restore()
+
+ restore = MockLinuxRawDeviceResourceManagedDevice(func(raw *linux.RawDevice) (*linux.RMDevice, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return nil, errors.New("some error")
+ })
+ defer restore()
+
+ restore = MockLinuxRMDeviceRawDevice(func(rm *linux.RMDevice) *linux.RawDevice {
+ c.Errorf("unexpected call to linux.RMDevice.RawDevice()")
+ return nil
+ })
+ defer restore()
+
+ _, err := DefaultDevice(DeviceModeTryResourceManaged)
+ c.Check(err, ErrorMatches, `some error`)
+}
+
+func (s *deviceLinuxSuite) TestDefaultDeviceResourceManaged(c *C) {
+ expectedRaw := new(linux.RawDevice)
+ expectedPPI := new(mockPPI)
+ expectedRM := new(linux.RMDevice)
+
+ restore := MockLinuxDefaultTPM2Device(func() (*linux.RawDevice, error) {
+ return expectedRaw, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDevicePhysicalPresenceInterface(func(raw *linux.RawDevice) (ppi.PPI, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return expectedPPI, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDeviceResourceManagedDevice(func(raw *linux.RawDevice) (*linux.RMDevice, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return expectedRM, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRMDeviceRawDevice(func(rm *linux.RMDevice) *linux.RawDevice {
+ c.Check(rm, Equals, expectedRM)
+ return expectedRaw
+ })
+ defer restore()
+
+ dev, err := DefaultDevice(DeviceModeResourceManaged)
+ c.Check(err, IsNil)
+ c.Check(dev, DeepEquals, NewTPMDevice(expectedRM, DeviceModeResourceManaged, expectedPPI, nil))
+}
+
+func (s *deviceLinuxSuite) TestDefaultDeviceResourceManagedNoRM(c *C) {
+ expectedRaw := new(linux.RawDevice)
+
+ restore := MockLinuxDefaultTPM2Device(func() (*linux.RawDevice, error) {
+ return expectedRaw, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDevicePhysicalPresenceInterface(func(raw *linux.RawDevice) (ppi.PPI, error) {
+ c.Errorf("unexpected call to linux.RawDevice.PhysicalPresenceInterface()")
+ return nil, nil
+ })
+ defer restore()
+
+ restore = MockLinuxRawDeviceResourceManagedDevice(func(raw *linux.RawDevice) (*linux.RMDevice, error) {
+ c.Check(raw, Equals, expectedRaw)
+ return nil, linux.ErrNoResourceManagedDevice
+ })
+ defer restore()
+
+ restore = MockLinuxRMDeviceRawDevice(func(rm *linux.RMDevice) *linux.RawDevice {
+ c.Errorf("unexpected call to linux.RMDevice.RawDevice()")
+ return nil
+ })
+ defer restore()
+
+ _, err := DefaultDevice(DeviceModeResourceManaged)
+ c.Check(err, Equals, ErrNoResourceManagedTPM2Device)
+}
diff --git a/internal/tpm2_device/device_test.go b/internal/tpm2_device/device_test.go
new file mode 100644
index 00000000..e6ba8cc6
--- /dev/null
+++ b/internal/tpm2_device/device_test.go
@@ -0,0 +1,88 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2024 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tpm2_device_test
+
+import (
+ "errors"
+ "testing"
+
+ "github.com/canonical/go-tpm2"
+ "github.com/canonical/go-tpm2/ppi"
+ . "github.com/snapcore/secboot/internal/tpm2_device"
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) { TestingT(t) }
+
+type mockTpmDevice struct{}
+
+func (mockTpmDevice) Open() (tpm2.Transport, error) {
+ return nil, errors.New("cannot open mock transport")
+}
+
+func (mockTpmDevice) String() string {
+ return "mock device"
+}
+
+type mockPPI struct {
+ ppi.PPI
+}
+
+type deviceSuite struct{}
+
+var _ = Suite(&deviceSuite{})
+
+func (s *deviceSuite) TestTPMDeviceDevice(c *C) {
+ dev := NewTPMDevice(new(mockTpmDevice), DeviceModeDirect, nil, ErrNoPPI)
+ c.Check(dev.String(), Equals, "mock device")
+ _, err := dev.Open()
+ c.Check(err, ErrorMatches, `cannot open mock transport`)
+}
+
+func (s *deviceSuite) TestTPMDeviceMode(c *C) {
+ dev := NewTPMDevice(new(mockTpmDevice), DeviceModeDirect, nil, ErrNoPPI)
+ c.Check(dev.Mode(), Equals, DeviceModeDirect)
+
+ dev = NewTPMDevice(new(mockTpmDevice), DeviceModeResourceManaged, nil, ErrNoPPI)
+ c.Check(dev.Mode(), Equals, DeviceModeResourceManaged)
+}
+
+func (s *deviceSuite) TestTPMDevicePPINone(c *C) {
+ dev := NewTPMDevice(new(mockTpmDevice), DeviceModeDirect, nil, nil)
+ ppi, err := dev.PPI()
+ c.Check(err, Equals, ErrNoPPI)
+ c.Check(ppi, IsNil)
+}
+
+func (s *deviceSuite) TestTPMDevicePPIErr(c *C) {
+ expected := errors.New("some error")
+ dev := NewTPMDevice(new(mockTpmDevice), DeviceModeDirect, nil, expected)
+ ppi, err := dev.PPI()
+ c.Check(err, Equals, expected)
+ c.Check(ppi, IsNil)
+}
+
+func (s *deviceSuite) TestTPMDevicePPI(c *C) {
+ expected := new(mockPPI)
+ dev := NewTPMDevice(new(mockTpmDevice), DeviceModeDirect, expected, nil)
+ ppi, err := dev.PPI()
+ c.Check(err, IsNil)
+ c.Check(ppi, Equals, expected)
+}
diff --git a/internal/tpm2_device/export_test.go b/internal/tpm2_device/export_test.go
new file mode 100644
index 00000000..b6326873
--- /dev/null
+++ b/internal/tpm2_device/export_test.go
@@ -0,0 +1,67 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2024 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package tpm2_device
+
+import (
+ "github.com/canonical/go-tpm2"
+ "github.com/canonical/go-tpm2/linux"
+ "github.com/canonical/go-tpm2/ppi"
+)
+
+func MockLinuxDefaultTPM2Device(fn func() (*linux.RawDevice, error)) (restore func()) {
+ orig := linuxDefaultTPM2Device
+ linuxDefaultTPM2Device = fn
+ return func() {
+ linuxDefaultTPM2Device = orig
+ }
+}
+
+func MockLinuxRawDeviceResourceManagedDevice(fn func(*linux.RawDevice) (*linux.RMDevice, error)) (restore func()) {
+ orig := linuxRawDeviceResourceManagedDevice
+ linuxRawDeviceResourceManagedDevice = fn
+ return func() {
+ linuxRawDeviceResourceManagedDevice = orig
+ }
+}
+
+func MockLinuxRawDevicePhysicalPresenceInterface(fn func(*linux.RawDevice) (ppi.PPI, error)) (restore func()) {
+ orig := linuxRawDevicePhysicalPresenceInterface
+ linuxRawDevicePhysicalPresenceInterface = fn
+ return func() {
+ linuxRawDevicePhysicalPresenceInterface = orig
+ }
+}
+
+func MockLinuxRMDeviceRawDevice(fn func(*linux.RMDevice) *linux.RawDevice) (restore func()) {
+ orig := linuxRMDeviceRawDevice
+ linuxRMDeviceRawDevice = fn
+ return func() {
+ linuxRMDeviceRawDevice = orig
+ }
+}
+
+func NewTPMDevice(dev tpm2.TPMDevice, mode DeviceMode, ppi ppi.PPI, ppiErr error) TPMDevice {
+ return &tpmDevice{
+ TPMDevice: dev,
+ mode: mode,
+ ppi: ppi,
+ ppiErr: ppiErr,
+ }
+}
diff --git a/internal/tpm2test/suites.go b/internal/tpm2test/suites.go
index 3e1083ea..87cc1b27 100644
--- a/internal/tpm2test/suites.go
+++ b/internal/tpm2test/suites.go
@@ -20,57 +20,80 @@
package tpm2test
import (
- "github.com/canonical/go-tpm2"
tpm2_testutil "github.com/canonical/go-tpm2/testutil"
. "gopkg.in/check.v1"
+ "github.com/snapcore/secboot/internal/testutil"
+ "github.com/snapcore/secboot/internal/tpm2_device"
secboot_tpm2 "github.com/snapcore/secboot/tpm2"
)
type tpmTestMixin struct {
- TPM *secboot_tpm2.Connection
- TCTI *TCTI
+ TPM *secboot_tpm2.Connection
+ Transport *Transport
}
-func (m *tpmTestMixin) setUpTest(c *C, open func() (*secboot_tpm2.Connection, *TCTI)) (cleanup func(*C)) {
- // Some tests execute code which calls secboot_tpm2.ConnectToTPM.
- // Allow this code to get a new secboot_tpm2.Connection using the
- // tests existing underlying connection, but don't allow the code
- // to fully close the connection - leave this to the test fixture.
- restoreOpenDefaultTcti := MockOpenDefaultTctiFn(func() (tpm2.TCTI, error) {
- tcti := WrapTCTI(m.TCTI.Unwrap().(*tpm2_testutil.TCTI))
- tcti.SetKeepOpen(true)
- return tcti, nil
- })
-
+func (m *tpmTestMixin) setUpTest(c *C, suite *tpm2_testutil.TPMTest, open func() (*secboot_tpm2.Connection, *Transport)) (cleanup func(*C)) {
switch {
case m.TPM != nil:
- // Allow the test to supply a secboot_tpm2.Connection
- c.Assert(m.TCTI, NotNil)
- case m.TCTI != nil:
- // Allow the test to supply an existing connection
- tpm, tcti, err := newTPMConnectionFromExisting(nil, m.TCTI)
+ // Allow the test to supply a secboot_tpm2.Connection via SetConnection
+ c.Assert(m.Transport, NotNil)
+ suite.TPM = m.TPM.TPMContext // Copy the tpm2.TPMContext to the TPMTest suite
+ suite.Transport = m.Transport.Unwrap().(*tpm2_testutil.Transport) // Copy the tpm2_testutil.Transport to the TPMTest suite
+ case m.Transport != nil:
+ // Allow the test to supply an existing transport, and create a connection from it
+ tpm, _, err := newTPMConnectionFromExistingTransport(nil, m.Transport)
c.Assert(err, IsNil)
m.TPM = tpm
- m.TCTI = tcti
+ suite.TPM = m.TPM.TPMContext // Copy the tpm2.TPMContext to the TPMTest suite
+ suite.Transport = m.Transport.Unwrap().(*tpm2_testutil.Transport) // Copy the tpm2_testutil.Transport to the TPMTest suite
+ case suite.Device != nil:
+ // Allow the test to supply a device, and create a connection from it
+ tpm, transport := OpenTPMDevice(c, suite.Device, nil, nil)
+ m.TPM = tpm
+ m.Transport = transport
+ suite.TPM = m.TPM.TPMContext // Copy the tpm2.TPMContext to the TPMTest suite
+ suite.Transport = m.Transport.Unwrap().(*tpm2_testutil.Transport) // Copy the tpm2_testutil.Transport to the TPMTest suite
default:
- m.TPM, m.TCTI = open()
+ // The default case - open a default connection
+ tpm, transport := open()
+ m.TPM = tpm
+ m.Transport = transport
+ suite.TPM = m.TPM.TPMContext // Copy the tpm2.TPMContext to the TPMTest suite
+ suite.Transport = m.Transport.Unwrap().(*tpm2_testutil.Transport) // Copy the tpm2_testutil.Transport to the TPMTest suite
}
+ // Some tests execute code which calls secboot_tpm2.ConnectToDefaultTPM.
+ // Allow this code to get a new secboot_tpm2.Connection using the
+ // tests existing underlying connection, but don't allow the code
+ // to fully close the connection - leave this to the test fixture.
+ // TODO: Support resource managed device concepts in tests.
+ // XXX: Set the maximum numbner of open connections to 1 when
+ // https://github.com/canonical/secboot/issues/353 is fixed.
+ internalDev := newTpmDevice(tpm2_testutil.NewTransportBackedDevice(suite.Transport, false, -1), tpm2_device.DeviceModeDirect, nil, tpm2_device.ErrNoPPI)
+ restoreDefaultDeviceFn := MockDefaultDeviceFn(func(mode tpm2_device.DeviceMode) (tpm2_device.TPMDevice, error) {
+ c.Assert(mode, Equals, tpm2_device.DeviceModeDirect)
+ return internalDev, nil
+ })
+
return func(c *C) {
- restoreOpenDefaultTcti()
+ restoreDefaultDeviceFn()
+ c.Check(internalDev.TPMDevice.(*tpm2_testutil.TransportBackedDevice).NumberOpen(), Equals, 0)
c.Check(m.TPM.Close(), IsNil)
- m.TCTI = nil
m.TPM = nil
+ m.Transport = nil
}
}
-func (m *tpmTestMixin) reinitTPMConnectionFromExisting(c *C) {
- tpm, tcti, err := newTPMConnectionFromExisting(m.TPM, m.TCTI)
+func (m *tpmTestMixin) reinitTPMConnectionFromExisting(c *C, suite *tpm2_testutil.TPMTest) {
+ tpm, transport, err := newTPMConnectionFromExistingTransport(m.TPM, m.Transport)
c.Assert(err, IsNil)
m.TPM = tpm
- m.TCTI = tcti
+ m.Transport = transport
+ suite.TPM = m.TPM.TPMContext // Copy the tpm2.TPMContext to the TPMTest suite
+ suite.Transport = m.Transport.Unwrap().(*tpm2_testutil.Transport) // Copy the tpm2_testutil.Transport to the TPMTest suite
+ suite.TCTI = suite.Transport // Fill the legacy member (this normally happens in tpm2_testutil.TPMTest.SetUpTest)
}
// TPMTest is a base test suite for all tests that require a TPM and are able to
@@ -83,60 +106,66 @@ type TPMTest struct {
}
// SetUpTest is called to set up the test fixture before each test. If
-// SetConnection has not been called before this is called, a TPM connection
-// will be created automatically. In this case, the TPMFeatures member should
-// be set prior to calling SetUpTest in order to declare the features that
-// the test will require. If the test requires any features that are not included
-// in tpm2_testutil.PermittedTPMFeatures, the test will be skipped. If
-// tpm2_testutil.TPMBackend is TPMBackendNone, then the test will be skipped.
+// SetConnection has not been called before this is called, or the Transport or
+// Device members have not been set, a TPM connection will be created automatically.
+// In this case, the TPMFeatures member should be set prior to calling SetUpTest in
+// order to declare the features that the test will require. If the test requires
+// any features that are not included in tpm2_testutil.PermittedTPMFeatures, the
+// test will be skipped. If tpm2_testutil.TPMBackend is TPMBackendNone, then the
+// test will be skipped.
+//
+// If SetConnection is called prior to calling SetUpTest, the supplied TPM connection
+// will be used for the test.
+//
+// If the Transport member is set prior to calling SetUpTest, a TPMContext is created
+// using this connection if necessary.
//
-// If SetConnection has been called with a test provided TCTI, then a connection
-// will be created from this.
+// If the Device member is set prior to calling SetUpTest, a TPM connection and
+// TPMContext is created using this.
//
// The TPM connection closed automatically when TearDownTest is called.
func (b *TPMTest) SetUpTest(c *C) {
// Don't support setting these directly as it makes things
// complicated.
c.Assert(b.TPMTest.TPM, IsNil)
+ c.Assert(b.TPMTest.Transport, IsNil)
c.Assert(b.TPMTest.TCTI, IsNil)
- cleanup := b.setUpTest(c, func() (*secboot_tpm2.Connection, *TCTI) {
- return OpenTPMConnection(c, b.TPMFeatures)
+ cleanup := b.setUpTest(c, &b.TPMTest, func() (*secboot_tpm2.Connection, *Transport) {
+ return OpenDefaultTPMConnection(c, b.TPMFeatures)
})
- b.TPMTest.TPM = b.tpmTestMixin.TPM.TPMContext
- b.TPMTest.TCTI = b.tpmTestMixin.TCTI.Unwrap().(*tpm2_testutil.TCTI)
-
b.TPMTest.SetUpTest(c)
b.AddFixtureCleanup(func(c *C) {
cleanup(c)
b.TPMTest.TPM = nil
b.TPMTest.TCTI = nil
+ b.TPMTest.Transport = nil
+ b.TPMTest.Device = nil
})
}
// SetConnection can be called prior to SetUpTest in order to supply a
// TPM connection rather than having the fixture create one.
-func (b *TPMTest) SetConnection(tpm *secboot_tpm2.Connection, tcti *TCTI) {
+func (b *TPMTest) SetConnection(c *C, tpm *secboot_tpm2.Connection) {
b.tpmTestMixin.TPM = tpm
- b.tpmTestMixin.TCTI = tcti
+ c.Assert(tpm.Transport(), testutil.ConvertibleTo, &Transport{})
+ b.tpmTestMixin.Transport = tpm.Transport().(*Transport)
}
func (b *TPMTest) TPM() *secboot_tpm2.Connection {
return b.tpmTestMixin.TPM
}
-func (b *TPMTest) TCTI() *TCTI {
- return b.tpmTestMixin.TCTI
+func (b *TPMTest) Transport() *Transport {
+ return b.tpmTestMixin.Transport
}
// ReinitTPMConnectionFromExisting recreates a new connection and TCTI
// from the existing ones. This is useful in scenarios where the fixture
// setup and test code should use a different connection.
func (b *TPMTest) ReinitTPMConnectionFromExisting(c *C) {
- b.reinitTPMConnectionFromExisting(c)
- b.TPMTest.TPM = b.tpmTestMixin.TPM.TPMContext
- b.TPMTest.TCTI = b.tpmTestMixin.TCTI.Unwrap().(*tpm2_testutil.TCTI)
+ b.reinitTPMConnectionFromExisting(c, &b.TPMTest)
}
// TPMSimulatorTest is a base test suite for all tests that require a TPM simulator.
@@ -148,12 +177,19 @@ type TPMSimulatorTest struct {
}
// SetUpTest is called to set up the test fixture before each test. If
-// SetConnection has not been called before this is called, a TPM simulator
-// connection will be created automatically. If tpm2_testutil.TPMBackend is
-// not TPMBackendMssim, then the test will be skipped.
+// SetConnection has not been called before this is called, or the Transport or
+// Device members have not been set, a TPM simulator connection will be created
+// automatically. If tpm2_testutil.TPMBackend is not TPMBackendMssim, then the test
+// will be skipped.
+//
+// If SetConnection is called prior to calling SetUpTest, the supplied TPM connection
+// will be used for the test.
//
-// If SetConnection has been called with a test provided TCTI, then a connection
-// will be created from this.
+// If the Transport member is set prior to calling SetUpTest, a TPMContext is created
+// using this connection if necessary.
+//
+// If the Device member is set prior to calling SetUpTest, a TPM connection and
+// TPMContext is created using this.
//
// When TearDownTest is called, the TPM simulator is reset and cleared
// and the connection is closed.
@@ -161,46 +197,45 @@ func (b *TPMSimulatorTest) SetUpTest(c *C) {
// Don't support setting these directly as it makes things
// complicated.
c.Assert(b.TPMTest.TPM, IsNil)
+ c.Assert(b.TPMTest.Transport, IsNil)
c.Assert(b.TPMTest.TCTI, IsNil)
- cleanup := b.setUpTest(c, func() (*secboot_tpm2.Connection, *TCTI) {
- return OpenTPMSimulatorConnection(c)
+ cleanup := b.setUpTest(c, &b.TPMTest, func() (*secboot_tpm2.Connection, *Transport) {
+ return OpenDefaultTPMSimulatorConnection(c)
})
- b.TPMTest.TPM = b.tpmTestMixin.TPM.TPMContext
- b.TPMTest.TCTI = b.tpmTestMixin.TCTI.Unwrap().(*tpm2_testutil.TCTI)
-
b.TPMSimulatorTest.SetUpTest(c)
b.AddFixtureCleanup(func(c *C) {
b.ResetAndClearTPMSimulatorUsingPlatformHierarchy(c)
cleanup(c)
b.TPMTest.TPM = nil
b.TPMTest.TCTI = nil
+ b.TPMTest.Transport = nil
+ b.TPMTest.Device = nil
})
}
// SetConnection can be called prior to SetUpTest in order to supply a
// TPM connection rather than having the fixture create one.
-func (b *TPMSimulatorTest) SetConnection(tpm *secboot_tpm2.Connection, tcti *TCTI) {
+func (b *TPMSimulatorTest) SetConnection(c *C, tpm *secboot_tpm2.Connection) {
b.tpmTestMixin.TPM = tpm
- b.tpmTestMixin.TCTI = tcti
+ c.Assert(tpm.Transport(), testutil.ConvertibleTo, &Transport{})
+ b.tpmTestMixin.Transport = tpm.Transport().(*Transport)
}
func (b *TPMSimulatorTest) TPM() *secboot_tpm2.Connection {
return b.tpmTestMixin.TPM
}
-func (b *TPMSimulatorTest) TCTI() *TCTI {
- return b.tpmTestMixin.TCTI
+func (b *TPMSimulatorTest) Transport() *Transport {
+ return b.tpmTestMixin.Transport
}
// ReinitTPMConnectionFromExisting recreates a new connection and TCTI
// from the existing ones. This is useful in scenarios where the fixture
// setup and test code should use a different connection.
func (b *TPMSimulatorTest) ReinitTPMConnectionFromExisting(c *C) {
- b.reinitTPMConnectionFromExisting(c)
- b.TPMTest.TPM = b.tpmTestMixin.TPM.TPMContext
- b.TPMTest.TCTI = b.tpmTestMixin.TCTI.Unwrap().(*tpm2_testutil.TCTI)
+ b.reinitTPMConnectionFromExisting(c, &b.TPMTest)
}
// ResetTPMSimulator issues a Shutdown -> Reset -> Startup cycle of the TPM simulator and
diff --git a/internal/tpm2test/tpm.go b/internal/tpm2test/tpm.go
index da0bf42a..6dc77ad9 100644
--- a/internal/tpm2test/tpm.go
+++ b/internal/tpm2test/tpm.go
@@ -20,15 +20,18 @@
package tpm2test
import (
+ "errors"
"testing"
"github.com/canonical/go-tpm2"
+ "github.com/canonical/go-tpm2/ppi"
tpm2_testutil "github.com/canonical/go-tpm2/testutil"
. "gopkg.in/check.v1"
"github.com/snapcore/secboot/internal/tcg"
- "github.com/snapcore/secboot/internal/tcti"
+ "github.com/snapcore/secboot/internal/testutil"
+ "github.com/snapcore/secboot/internal/tpm2_device"
secboot_tpm2 "github.com/snapcore/secboot/tpm2"
)
@@ -81,13 +84,13 @@ const (
//TPMFeaturePersistent = tpm2_testutil.TPMFeaturePersistent
)
-// MockOpenDefaultTctiFn overrides the tcti.OpenDefault function, used
-// to create a connection to the default TPM.
-func MockOpenDefaultTctiFn(fn func() (tpm2.TCTI, error)) (restore func()) {
- origFn := tcti.OpenDefault
- tcti.OpenDefault = fn
+// MockDefaultDeviceFn overrides the tpm2_device.DefaultDevice function, used
+// to obtain the default TPM device.
+func MockDefaultDeviceFn(fn func(tpm2_device.DeviceMode) (tpm2_device.TPMDevice, error)) (restore func()) {
+ orig := tpm2_device.DefaultDevice
+ tpm2_device.DefaultDevice = fn
return func() {
- tcti.OpenDefault = origFn
+ tpm2_device.DefaultDevice = orig
}
}
@@ -101,53 +104,126 @@ func MockEKTemplate(mock *tpm2.Public) (restore func()) {
}
}
-// OpenTPMSimulatorConnection returns a new TPM connection to the TPM simulator on
-// the port specified by tpm2_testutil.MssimPort. If tpm2_testutil.TPMBackend is
-// not TPMBackendMssim then the test will be skipped.
-//
-// The returned connection must be closed when it is no longer required.
-func OpenTPMSimulatorConnection(c *C) (tpm *secboot_tpm2.Connection, tcti *TCTI) {
- tcti = WrapTCTI(tpm2_testutil.NewSimulatorTCTI(c))
+type testTpmDevice struct {
+ tpm2.TPMDevice
+}
- restore := MockOpenDefaultTctiFn(func() (tpm2.TCTI, error) {
- return tcti, nil
- })
- defer restore()
+func newTestTpmDevice(dev tpm2.TPMDevice) *testTpmDevice {
+ return &testTpmDevice{TPMDevice: dev}
+}
- tpm, err := secboot_tpm2.ConnectToTPM()
- c.Assert(err, IsNil)
+func (d *testTpmDevice) Open() (tpm2.Transport, error) {
+ transport, err := d.TPMDevice.Open()
+ if err != nil {
+ return nil, err
+ }
+ testTransport, ok := transport.(*tpm2_testutil.Transport)
+ if !ok {
+ return nil, errors.New("expected a tpm2_testutil.Transport")
+ }
+ return WrapTransport(testTransport), nil
+}
- return tpm, tcti
+type tpmDevice struct {
+ tpm2.TPMDevice
+ mode tpm2_device.DeviceMode
+ ppi ppi.PPI
+ ppiErr error
}
-// OpenTPMSimulatorConnectionT returns a new TPM connection to the TPM simulator
-// on the port specified by tpm2_testutil.MssimPort. If tpm2_testutil.TPMBackend is
-// not TPMBackendMssim then the test will be skipped.
-//
-// The returned connection must be closed when it is no longer required. This can
-// be done with the returned close callback, which will cause the test to fail if
-// closing doesn't succeed.
-func OpenTPMSimulatorConnectionT(t *testing.T) (tpm *secboot_tpm2.Connection, tcti *TCTI, close func()) {
- tcti = WrapTCTI(tpm2_testutil.NewSimulatorTCTIT(t))
+func newTpmDevice(dev tpm2.TPMDevice, mode tpm2_device.DeviceMode, ppi ppi.PPI, ppiErr error) *tpmDevice {
+ return &tpmDevice{
+ TPMDevice: dev,
+ mode: mode,
+ ppi: ppi,
+ ppiErr: ppiErr,
+ }
+}
+
+func (d *tpmDevice) Mode() tpm2_device.DeviceMode {
+ return d.mode
+}
+
+func (d *tpmDevice) PPI() (ppi.PPI, error) {
+ return d.ppi, d.ppiErr
+}
- restore := MockOpenDefaultTctiFn(func() (tpm2.TCTI, error) {
- return tcti, nil
+func openTPMDevice(dev tpm2.TPMDevice, ppi ppi.PPI, ppiErr error) (tpm *secboot_tpm2.Connection, err error) {
+ restore := MockDefaultDeviceFn(func(mode tpm2_device.DeviceMode) (tpm2_device.TPMDevice, error) {
+ if mode != tpm2_device.DeviceModeDirect {
+ // TODO: Support other modes here
+ return nil, errors.New("unexpected mode")
+ }
+ if ppi == nil && ppiErr == nil {
+ ppiErr = tpm2_device.ErrNoPPI
+ }
+ return newTpmDevice(newTestTpmDevice(dev), mode, ppi, ppiErr), nil
})
defer restore()
- tpm, err := secboot_tpm2.ConnectToTPM()
+ tpm, err = secboot_tpm2.ConnectToDefaultTPM()
+ if err != nil {
+ return nil, err
+ }
+
+ return tpm, nil
+}
+
+func OpenTPMDevice(c *C, dev tpm2.TPMDevice, ppi ppi.PPI, ppiErr error) (tpm *secboot_tpm2.Connection, transport *Transport) {
+ tpm, err := openTPMDevice(dev, ppi, ppiErr)
+ if errors.Is(err, tpm2_testutil.ErrSkipNoTPM) {
+ c.Skip("no TPM available for the test")
+ }
+ c.Assert(err, IsNil)
+ c.Assert(tpm.Transport(), testutil.ConvertibleTo, &Transport{})
+
+ return tpm, tpm.Transport().(*Transport)
+}
+
+func OpenTPMDeviceT(t *testing.T, dev tpm2.TPMDevice, ppi ppi.PPI, ppiErr error) (tpm *secboot_tpm2.Connection, transport *Transport, close func()) {
+ tpm, err := openTPMDevice(dev, ppi, ppiErr)
+ if errors.Is(err, tpm2_testutil.ErrSkipNoTPM) {
+ t.SkipNow()
+ }
if err != nil {
t.Fatalf("%v", err)
}
- return tpm, tcti, func() {
+ transport, ok := tpm.Transport().(*Transport)
+ if !ok {
+ t.Fatal("unexpected transport type")
+ }
+
+ return tpm, transport, func() {
if err := tpm.Close(); err != nil {
t.Errorf("close failed: %v", err)
}
}
}
-// OpenTPMConnection returns a new TPM connection for testing. If tpm2_testutil.TPMBackend
+// OpenDefaultTPMSimulatorConnection returns a new TPM connection to the TPM simulator on
+// the port specified by tpm2_testutil.MssimPort. If tpm2_testutil.TPMBackend is
+// not TPMBackendMssim then the test will be skipped.
+//
+// The returned connection must be closed when it is no longer required.
+func OpenDefaultTPMSimulatorConnection(c *C) (tpm *secboot_tpm2.Connection, transport *Transport) {
+ // TODO: Support supplying a ppi.PPI implementation that can be tested.
+ return OpenTPMDevice(c, tpm2_testutil.NewSimulatorDevice(), nil, nil)
+}
+
+// OpenDefaultTPMSimulatorConnectionT returns a new TPM connection to the TPM simulator
+// on the port specified by tpm2_testutil.MssimPort. If tpm2_testutil.TPMBackend is
+// not TPMBackendMssim then the test will be skipped.
+//
+// The returned connection must be closed when it is no longer required. This can
+// be done with the returned close callback, which will cause the test to fail if
+// closing doesn't succeed.
+func OpenDefaultTPMSimulatorConnectionT(t *testing.T) (tpm *secboot_tpm2.Connection, transport *Transport, close func()) {
+ // TODO: Support supplying a ppi.PPI implementation that can be tested.
+ return OpenTPMDeviceT(t, tpm2_testutil.NewSimulatorDevice(), nil, nil)
+}
+
+// OpenDefaultTPMConnection returns a new TPM connection for testing. If tpm2_testutil.TPMBackend
// is TPMBackendNone then the current test will be skipped. If tpm2_testutil.TPMBackend
// is TPMBackendMssim, the returned context will correspond to a connection to the TPM
// simulator on the port specified by the tpm2_testutil.MssimPort variable. If
@@ -158,21 +234,12 @@ func OpenTPMSimulatorConnectionT(t *testing.T) (tpm *secboot_tpm2.Connection, tc
// If the test requires features that are not permitted, the test will be skipped.
//
// The returned connection must be closed when it is no longer required.
-func OpenTPMConnection(c *C, features tpm2_testutil.TPMFeatureFlags) (tpm *secboot_tpm2.Connection, tcti *TCTI) {
- tcti = WrapTCTI(tpm2_testutil.NewTCTI(c, features))
-
- restore := MockOpenDefaultTctiFn(func() (tpm2.TCTI, error) {
- return tcti, nil
- })
- defer restore()
-
- tpm, err := secboot_tpm2.ConnectToTPM()
- c.Assert(err, IsNil)
-
- return tpm, tcti
+func OpenDefaultTPMConnection(c *C, features tpm2_testutil.TPMFeatureFlags) (tpm *secboot_tpm2.Connection, transport *Transport) {
+ // TODO: Support supplying a ppi.PPI implementation that can be tested.
+ return OpenTPMDevice(c, tpm2_testutil.NewDevice(c, features), nil, nil)
}
-// OpenTPMConnectionT returns a new TPM connection for testing. If tpm2_testutil.TPMBackend
+// OpenDefaultTPMConnectionT returns a new TPM connection for testing. If tpm2_testutil.TPMBackend
// is TPMBackendNone then the current test will be skipped. If tpm2_testutil.TPMBackend
// is TPMBackendMssim, the returned context will correspond to a connection to the TPM
// simulator on the port specified by the tpm2_testutil.MssimPort variable. If
@@ -185,51 +252,45 @@ func OpenTPMConnection(c *C, features tpm2_testutil.TPMFeatureFlags) (tpm *secbo
// The returned connection must be closed when it is no longer required. This can be
// done with the returned close callback, which will cause the test to fail if closing
// doesn't succeed.
-func OpenTPMConnectionT(t *testing.T, features tpm2_testutil.TPMFeatureFlags) (tpm *secboot_tpm2.Connection, tcti *TCTI, close func()) {
- tcti = WrapTCTI(tpm2_testutil.NewTCTIT(t, features))
-
- restore := MockOpenDefaultTctiFn(func() (tpm2.TCTI, error) {
- return tcti, nil
- })
- defer restore()
-
- tpm, err := secboot_tpm2.ConnectToTPM()
- if err != nil {
- t.Fatalf("%v", err)
- }
-
- return tpm, tcti, func() {
- if err := tpm.Close(); err != nil {
- t.Errorf("close failed: %v", err)
- }
- }
+func OpenDefaultTPMConnectionT(t *testing.T, features tpm2_testutil.TPMFeatureFlags) (tpm *secboot_tpm2.Connection, transport *Transport, close func()) {
+ // TODO: Support supplying a ppi.PPI implementation that can be tested.
+ return OpenTPMDeviceT(t, tpm2_testutil.NewDeviceT(t, features), nil, nil)
}
-func newTPMConnectionFromExisting(tpm *secboot_tpm2.Connection, tcti *TCTI) (*secboot_tpm2.Connection, *TCTI, error) {
+func newTPMConnectionFromExistingTransport(tpm *secboot_tpm2.Connection, transport *Transport) (*secboot_tpm2.Connection, *Transport, error) {
+ // Wrap the supplied transport in a TPMDevice.
+ dev := tpm2_testutil.NewTransportPassthroughDevice(transport.Unwrap())
+
if tpm != nil {
+ // A TPM Connection was supplied. Pretend to close the existing connection,
+ // which flushes the HMAC session associated with it. This will close the
+ // test transport, but we keep the underlying transport open.
+ if transport != tpm.Transport() {
+ return nil, nil, errors.New("invalid transport")
+ }
// Pretend to close the existing connection, which flushes
// the HMAC session associated with it.
- tcti.SetKeepOpen(true)
+ transport.SetKeepOpen(true)
if err := tpm.Close(); err != nil {
return nil, nil, err
}
- }
- // Create a new tcti, using the same underlyinhg connection.
- tcti = WrapTCTI(tcti.Unwrap().(*tpm2_testutil.TCTI))
+ // Create another device based on the same underlying transport.
+ dev = tpm2_testutil.NewTransportPassthroughDevice(transport.Unwrap())
+ }
- restore := MockOpenDefaultTctiFn(func() (tpm2.TCTI, error) {
- return tcti, nil
+ restore := MockDefaultDeviceFn(func(mode tpm2_device.DeviceMode) (tpm2_device.TPMDevice, error) {
+ return newTpmDevice(newTestTpmDevice(dev), mode, nil, tpm2_device.ErrNoPPI), nil
})
defer restore()
- // Create a new connection.
- tpm, err := secboot_tpm2.ConnectToTPM()
+ // Create a new connection using the existing transport.
+ tpm, err := secboot_tpm2.ConnectToDefaultTPM()
if err != nil {
- tcti.Close()
+ transport.Close()
}
- return tpm, tcti, err
+ return tpm, tpm.Transport().(*Transport), err
}
// NewTPMConnectionFromExistingT creates a new connection and TCTI from the
@@ -237,13 +298,13 @@ func newTPMConnectionFromExisting(tpm *secboot_tpm2.Connection, tcti *TCTI) (*se
// test execution require a different connection. The returned connection
// uses the same underlying connection as the one supplied. The supplied
// source connection does not need to be closed afterwards.
-func NewTPMConnectionFromExistingT(t *testing.T, tpm *secboot_tpm2.Connection, tcti *TCTI) (newTpm *secboot_tpm2.Connection, newTcti *TCTI, close func()) {
- tpm, tcti, err := newTPMConnectionFromExisting(tpm, tcti)
+func NewTPMConnectionFromExistingTransportT(t *testing.T, tpm *secboot_tpm2.Connection, transport *Transport) (newTpm *secboot_tpm2.Connection, newTransport *Transport, close func()) {
+ newTpm, newTransport, err := newTPMConnectionFromExistingTransport(tpm, transport)
if err != nil {
t.Fatal(err)
}
- return tpm, tcti, func() {
- if err := tpm.Close(); err != nil {
+ return newTpm, newTransport, func() {
+ if err := newTpm.Close(); err != nil {
t.Errorf("close failed: %v", err)
}
}
@@ -252,7 +313,7 @@ func NewTPMConnectionFromExistingT(t *testing.T, tpm *secboot_tpm2.Connection, t
// ResetTPMSimulatorT issues a Shutdown -> Reset -> Startup cycle of the TPM
// simulator and returns a newly initialized TPM connection. The supplied
// source connection does not need to be closed afterwards.
-func ResetTPMSimulatorT(t *testing.T, tpm *secboot_tpm2.Connection, tcti *TCTI) (newTpm *secboot_tpm2.Connection, newTcti *TCTI, close func()) {
- tpm2_testutil.ResetTPMSimulatorT(t, tpm.TPMContext, tcti.Unwrap().(*tpm2_testutil.TCTI))
- return NewTPMConnectionFromExistingT(t, tpm, tcti)
+func ResetTPMSimulatorT(t *testing.T, tpm *secboot_tpm2.Connection, transport *Transport) (newTpm *secboot_tpm2.Connection, newTransport *Transport, close func()) {
+ tpm2_testutil.ResetTPMSimulatorT(t, tpm.TPMContext, transport.Unwrap().(*tpm2_testutil.Transport))
+ return NewTPMConnectionFromExistingTransportT(t, tpm, transport)
}
diff --git a/internal/tpm2test/tcti.go b/internal/tpm2test/transport.go
similarity index 69%
rename from internal/tpm2test/tcti.go
rename to internal/tpm2test/transport.go
index 244a3034..d15afa85 100644
--- a/internal/tpm2test/tcti.go
+++ b/internal/tpm2test/transport.go
@@ -20,48 +20,46 @@
package tpm2test
import (
- "os"
-
"github.com/canonical/go-tpm2"
tpm2_testutil "github.com/canonical/go-tpm2/testutil"
)
-// TCTI is a wrapper around tpm2_testutil.TCTI that provides a mechanism
+// Transport is a wrapper around tpm2_testutil.Transport that provides a mechanism
// to keep the underlying connection open when Close is called.
-type TCTI struct {
- tcti *tpm2_testutil.TCTI
+type Transport struct {
+ transport *tpm2_testutil.Transport
keepOpen bool
markedClosed bool
closed bool
}
-func (t *TCTI) Read(data []byte) (int, error) {
+func (t *Transport) Read(data []byte) (int, error) {
if t.markedClosed {
- return 0, os.ErrClosed
+ return 0, tpm2.ErrTransportClosed
}
- return t.tcti.Read(data)
+ return t.transport.Read(data)
}
-func (t *TCTI) Write(data []byte) (int, error) {
+func (t *Transport) Write(data []byte) (int, error) {
if t.markedClosed {
- return 0, os.ErrClosed
+ return 0, tpm2.ErrTransportClosed
}
- return t.tcti.Write(data)
+ return t.transport.Write(data)
}
// Close closes the underlying connection unless SetKeepOpen has
// been called with keepOpen set to true, in which case, the
// interface is marked as closed without actually closing it.
-func (t *TCTI) Close() error {
+func (t *Transport) Close() error {
if t.markedClosed {
- return os.ErrClosed
+ return tpm2.ErrTransportClosed
}
t.markedClosed = true
if t.keepOpen {
return nil
}
t.closed = true
- return t.tcti.Close()
+ return t.transport.Close()
}
// SetKeepOpen provides a mechanism to keep the underlying connection
@@ -69,19 +67,19 @@ func (t *TCTI) Close() error {
// mark the connection as closed without actually closing it. This
// makes it possible to reuse the underlying connection in another
// secboot_tpm2.Connection.
-func (t *TCTI) SetKeepOpen(keepOpen bool) error {
+func (t *Transport) SetKeepOpen(keepOpen bool) error {
t.keepOpen = keepOpen
if !t.keepOpen && t.markedClosed && !t.closed {
t.closed = true
- return t.tcti.Close()
+ return t.transport.Close()
}
return nil
}
-func (t *TCTI) Unwrap() tpm2.TCTI {
- return t.tcti
+func (t *Transport) Unwrap() tpm2.Transport {
+ return t.transport
}
-func WrapTCTI(tcti *tpm2_testutil.TCTI) *TCTI {
- return &TCTI{tcti: tcti}
+func WrapTransport(transport *tpm2_testutil.Transport) *Transport {
+ return &Transport{transport: transport}
}
diff --git a/tpm2/errors.go b/tpm2/errors.go
index e2aecbbe..b758ac0f 100644
--- a/tpm2/errors.go
+++ b/tpm2/errors.go
@@ -24,6 +24,7 @@ import (
"fmt"
"github.com/canonical/go-tpm2"
+ "github.com/snapcore/secboot/internal/tpm2_device"
"golang.org/x/xerrors"
)
@@ -48,8 +49,8 @@ var (
// the TPM (eg, a recovery key)
ErrTPMLockout = errors.New("the TPM is in DA lockout mode")
- // ErrNoTPM2Device is returned from ConnectToDefaultTPM or SecureConnectToDefaultTPM if no TPM2 device is avaiable.
- ErrNoTPM2Device = errors.New("no TPM2 device is available")
+ // ErrNoTPM2Device is returned from ConnectToDefaultTPM if no TPM2 device is avaiable.
+ ErrNoTPM2Device = tpm2_device.ErrNoTPM2Device
)
// TPMResourceExistsError is returned from any function that creates a persistent TPM resource if a resource already exists
diff --git a/tpm2/platform.go b/tpm2/platform.go
index 3f324222..b504699e 100644
--- a/tpm2/platform.go
+++ b/tpm2/platform.go
@@ -67,7 +67,7 @@ func (h *platformKeyDataHandler) recoverKeysCommon(data *secboot.PlatformKeyData
Err: fmt.Errorf("invalid key data version: %d", k.data.Version())}
}
- tpm, err := ConnectToTPM()
+ tpm, err := ConnectToDefaultTPM()
switch {
case err == ErrNoTPM2Device:
return nil, &secboot.PlatformHandlerError{
@@ -121,7 +121,7 @@ func (h *platformKeyDataHandler) RecoverKeysWithAuthKey(data *secboot.PlatformKe
}
func (h *platformKeyDataHandler) ChangeAuthKey(data *secboot.PlatformKeyData, old, new []byte) ([]byte, error) {
- tpm, err := ConnectToTPM()
+ tpm, err := ConnectToDefaultTPM()
switch {
case err == ErrNoTPM2Device:
return nil, &secboot.PlatformHandlerError{
diff --git a/tpm2/platform_legacy.go b/tpm2/platform_legacy.go
index 2f54bd64..55e881f0 100644
--- a/tpm2/platform_legacy.go
+++ b/tpm2/platform_legacy.go
@@ -53,7 +53,7 @@ const legacyPlatformName = "tpm2-legacy"
type legacyPlatformKeyDataHandler struct{}
func (h *legacyPlatformKeyDataHandler) RecoverKeys(data *secboot.PlatformKeyData, encryptedPayload []byte) ([]byte, error) {
- tpm, err := ConnectToTPM()
+ tpm, err := ConnectToDefaultTPM()
switch {
case err == ErrNoTPM2Device:
return nil, &secboot.PlatformHandlerError{
diff --git a/tpm2/platform_legacy_test.go b/tpm2/platform_legacy_test.go
index c39557e4..dd89ecf1 100644
--- a/tpm2/platform_legacy_test.go
+++ b/tpm2/platform_legacy_test.go
@@ -21,9 +21,7 @@ package tpm2_test
import (
"math/rand"
- "os"
"path/filepath"
- "syscall"
"github.com/canonical/go-tpm2"
@@ -31,6 +29,7 @@ import (
"github.com/snapcore/secboot"
"github.com/snapcore/secboot/internal/tcg"
+ "github.com/snapcore/secboot/internal/tpm2_device"
"github.com/snapcore/secboot/internal/tpm2test"
. "github.com/snapcore/secboot/tpm2"
)
@@ -84,8 +83,8 @@ func (s *platformLegacySuite) TestRecoverKeysNoTPMConnection(c *C) {
PCRPolicyCounterHandle: tpm2.HandleNull})
c.Check(err, IsNil)
- restore := tpm2test.MockOpenDefaultTctiFn(func() (tpm2.TCTI, error) {
- return nil, &os.PathError{Op: "open", Path: "/dev/tpm0", Err: syscall.ENOENT}
+ restore := tpm2test.MockDefaultDeviceFn(func(tpm2_device.DeviceMode) (tpm2_device.TPMDevice, error) {
+ return nil, tpm2_device.ErrNoTPM2Device
})
s.AddCleanup(restore)
diff --git a/tpm2/platform_test.go b/tpm2/platform_test.go
index 7ecfd865..84ddd66c 100644
--- a/tpm2/platform_test.go
+++ b/tpm2/platform_test.go
@@ -25,8 +25,6 @@ import (
gohash "hash"
"io"
"math/rand"
- "os"
- "syscall"
"github.com/canonical/go-tpm2"
"github.com/canonical/go-tpm2/util"
@@ -39,6 +37,7 @@ import (
"github.com/snapcore/secboot"
"github.com/snapcore/secboot/internal/tcg"
"github.com/snapcore/secboot/internal/testutil"
+ "github.com/snapcore/secboot/internal/tpm2_device"
"github.com/snapcore/secboot/internal/tpm2test"
. "github.com/snapcore/secboot/tpm2"
)
@@ -376,8 +375,8 @@ func (s *platformSuite) TestRecoverKeysNoTPMConnection(c *C) {
})
c.Check(err, IsNil)
- restore := tpm2test.MockOpenDefaultTctiFn(func() (tpm2.TCTI, error) {
- return nil, &os.PathError{Op: "open", Path: "/dev/tpm0", Err: syscall.ENOENT}
+ restore := tpm2test.MockDefaultDeviceFn(func(tpm2_device.DeviceMode) (tpm2_device.TPMDevice, error) {
+ return nil, tpm2_device.ErrNoTPM2Device
})
s.AddCleanup(restore)
diff --git a/tpm2/tpm.go b/tpm2/tpm.go
index a2238935..c1ce6df6 100644
--- a/tpm2/tpm.go
+++ b/tpm2/tpm.go
@@ -27,7 +27,7 @@ import (
"golang.org/x/xerrors"
"github.com/snapcore/secboot/internal/tcg"
- "github.com/snapcore/secboot/internal/tcti"
+ "github.com/snapcore/secboot/internal/tpm2_device"
)
// Connection corresponds to a connection to a TPM device, and is a wrapper around *tpm2.TPMContext.
@@ -132,15 +132,15 @@ func (t *Connection) init() (err error) {
// connectToDefaultTPM opens a connection to the default TPM device.
func connectToDefaultTPM() (*tpm2.TPMContext, error) {
- tcti, err := tcti.OpenDefault()
+ dev, err := tpm2_device.DefaultDevice(tpm2_device.DeviceModeDirect)
if err != nil {
- if isPathError(err) {
- return nil, ErrNoTPM2Device
- }
- return nil, xerrors.Errorf("cannot open TPM device: %w", err)
+ return nil, err
}
- tpm := tpm2.NewTPMContext(tcti)
+ tpm, err := tpm2.OpenTPMDevice(dev)
+ if err != nil {
+ return nil, err
+ }
if !tpm.IsTPM2() {
tpm.Close()
return nil, ErrNoTPM2Device
@@ -149,10 +149,7 @@ func connectToDefaultTPM() (*tpm2.TPMContext, error) {
return tpm, nil
}
-// ConnectToDefaultTPM will attempt to connect to the default TPM. It makes no attempt to verify the authenticity of the TPM. This
-// function is useful for connecting to a device that isn't correctly provisioned and for which the endorsement hierarchy
-// authorization value is unknown (so that it can be cleared), or for connecting to a device in order to execute
-// FetchAndSaveEKCertificateChain. It should not be used in any other scenario.
+// ConnectToDefaultTPM will attempt to connect to the default TPM2 device.
//
// If no TPM2 device is available, then a ErrNoTPM2Device error will be returned.
func ConnectToDefaultTPM() (*Connection, error) {
@@ -178,10 +175,3 @@ func ConnectToDefaultTPM() (*Connection, error) {
succeeded = true
return t, nil
}
-
-// ConnectToTPM will attempt to connect to a TPM using the currently
-// defined connection function. This is used internally by the tpm2
-// package when a connection is required, and defaults to
-// ConnectToDefaultTPM. This can be overridden with a custom connection
-// function.
-var ConnectToTPM func() (*Connection, error) = ConnectToDefaultTPM
diff --git a/tpm2/tpm_test.go b/tpm2/tpm_test.go
index 76389f12..41ac8816 100644
--- a/tpm2/tpm_test.go
+++ b/tpm2/tpm_test.go
@@ -20,14 +20,9 @@
package tpm2_test
import (
- "bytes"
"crypto/x509"
- "io"
- "os"
- "syscall"
"github.com/canonical/go-tpm2"
- "github.com/canonical/go-tpm2/mu"
"github.com/canonical/go-tpm2/templates"
tpm2_testutil "github.com/canonical/go-tpm2/testutil"
@@ -35,6 +30,7 @@ import (
"github.com/snapcore/secboot/internal/tcg"
"github.com/snapcore/secboot/internal/testutil"
+ "github.com/snapcore/secboot/internal/tpm2_device"
"github.com/snapcore/secboot/internal/tpm2test"
. "github.com/snapcore/secboot/tpm2"
)
@@ -154,53 +150,8 @@ func (s *tpmSuite) TestConnectToDefaultTPMInvalidEK(c *C) {
}
func (s *tpmSuiteNoTPM) TestConnectToDefaultTPMNoTPM(c *C) {
- restore := tpm2test.MockOpenDefaultTctiFn(func() (tpm2.TCTI, error) {
- return nil, &os.PathError{Op: "open", Path: "/dev/tpm0", Err: syscall.ENOENT}
- })
- s.AddCleanup(restore)
-
- tpm, err := ConnectToDefaultTPM()
- c.Check(err, Equals, ErrNoTPM2Device)
- c.Check(tpm, IsNil)
-}
-
-// We don't have a TPM1.2 simulator, so create a mock TCTI that just returns
-// a TPM_BAD_ORDINAL error
-type mockTPM12Transport struct {
- rsp io.Reader
-}
-
-func (t *mockTPM12Transport) Read(data []byte) (int, error) {
- for {
- n, err := t.rsp.Read(data)
- if err == io.EOF {
- t.rsp = nil
- err = nil
- if n == 0 {
- continue
- }
- }
- return n, err
- }
-}
-
-func (t *mockTPM12Transport) Write(data []byte) (int, error) {
- buf := new(bytes.Buffer)
- // tag = TPM_TAG_RSP_COMMAND (0xc4)
- // paramSize = 10
- // returnCode = TPM_BAD_ORDINAL (10)
- mu.MustMarshalToWriter(buf, tpm2.TagRspCommand, uint32(10), tpm2.ResponseBadTag)
- t.rsp = buf
- return len(data), nil
-}
-
-func (t *mockTPM12Transport) Close() error {
- return nil
-}
-
-func (s *tpmSuiteNoTPM) TestConnectToDefaultTPM12(c *C) {
- restore := tpm2test.MockOpenDefaultTctiFn(func() (tpm2.TCTI, error) {
- return &mockTPM12Transport{}, nil
+ restore := tpm2test.MockDefaultDeviceFn(func(tpm2_device.DeviceMode) (tpm2_device.TPMDevice, error) {
+ return nil, tpm2_device.ErrNoTPM2Device
})
s.AddCleanup(restore)