diff --git a/go.mod b/go.mod index f9b6fc110d5..9abe5fb575d 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,9 @@ replace maze.io/x/crypto => github.com/snapcore/maze.io-x-crypto v0.0.0-20190131 require ( github.com/bmatcuk/doublestar/v4 v4.6.1 - github.com/canonical/go-efilib v1.3.1 + github.com/canonical/go-efilib v1.4.1 github.com/canonical/go-sp800.90a-drbg v0.0.0-20210314144037-6eeb1040d6c3 // indirect - github.com/canonical/go-tpm2 v1.7.6 + github.com/canonical/go-tpm2 v1.11.1 github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 github.com/gorilla/mux v1.8.0 @@ -21,11 +21,11 @@ require ( github.com/mvo5/libseccomp-golang v0.9.1-0.20180308152521-f4de83b52afb // old trusty builds only github.com/seccomp/libseccomp-golang v0.9.2-0.20220502024300-f57e1d55ea18 github.com/snapcore/go-gettext v0.0.0-20191107141714-82bbea49e785 - github.com/snapcore/secboot v0.0.0-20241115151056-b3ae5175dc9b - golang.org/x/crypto v0.21.0 + github.com/snapcore/secboot v0.0.0-20250124132100-452552189677 + golang.org/x/crypto v0.23.0 golang.org/x/net v0.21.0 // indirect - golang.org/x/sys v0.19.0 - golang.org/x/text v0.14.0 + golang.org/x/sys v0.21.0 + golang.org/x/text v0.15.0 golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/macaroon.v1 v1.0.0 @@ -39,11 +39,11 @@ require go.etcd.io/bbolt v1.3.9 require ( github.com/canonical/cpuid v0.0.0-20220614022739-219e067757cb // indirect - github.com/canonical/go-sp800.108-kdf v0.0.0-20210315104021-ead800bbf9a0 // indirect + github.com/canonical/go-kbkdf v0.0.0-20250104172618-3b1308f9acf9 // indirect github.com/canonical/tcglog-parser v0.0.0-20240924110432-d15eaf652981 // indirect github.com/kr/pretty v0.2.2-0.20200810074440-814ac30b4b18 // indirect github.com/kr/text v0.1.0 // indirect golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect - golang.org/x/term v0.18.0 // indirect + golang.org/x/term v0.20.0 // indirect maze.io/x/crypto v0.0.0-20190131090603-9b94c9afe066 // indirect ) diff --git a/go.sum b/go.sum index 4abebba3921..eb49554c385 100644 --- a/go.sum +++ b/go.sum @@ -2,14 +2,14 @@ github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwN github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/canonical/cpuid v0.0.0-20220614022739-219e067757cb h1:+kA/9oHTqUx4P08ywKvmd7a1wOL3RLTrE0K958C15x8= github.com/canonical/cpuid v0.0.0-20220614022739-219e067757cb/go.mod h1:6j8Sw3dwYVcBXltEeGklDoK/8UJVJNQPUkg1ZdQUgbk= -github.com/canonical/go-efilib v1.3.1 h1:KnVlqrKn0ZDGAbgQt9tke5cvtqNRCmpEp0v7RGUVpqs= -github.com/canonical/go-efilib v1.3.1/go.mod h1:n0Ttsy1JuHAvqaFbZBs6PAzoiiJdfkHsAmDOEbexYEQ= -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-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.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 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.11.1 h1:RivdSXfBWWW+eFaFNYQby5+kVgY4km9eEayot1wX/qU= +github.com/canonical/go-tpm2 v1.11.1/go.mod h1:zK+qESVwu78XyX+NPhiBdN+zwPPDoKk4rYlQ7VUsRp4= 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= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= @@ -49,15 +49,15 @@ github.com/snapcore/go-gettext v0.0.0-20191107141714-82bbea49e785 h1:PaunR+BhraK github.com/snapcore/go-gettext v0.0.0-20191107141714-82bbea49e785/go.mod h1:D3SsWAXK7wCCBZu+Vk5hc1EuKj/L3XN1puEMXTU4LrQ= github.com/snapcore/maze.io-x-crypto v0.0.0-20190131090603-9b94c9afe066 h1:InG0EmriMOiI4YgtQNOo+6fNxzLCYioo3Q3BCVLdMCE= github.com/snapcore/maze.io-x-crypto v0.0.0-20190131090603-9b94c9afe066/go.mod h1:VuAdaITF1MrGzxPU+8GxagM1HW2vg7QhEFEeGHbmEMU= -github.com/snapcore/secboot v0.0.0-20241115151056-b3ae5175dc9b h1:ywW6AgHzAVjJIlkDLb+52IgEXVFYxG2rzjP34khWbow= -github.com/snapcore/secboot v0.0.0-20241115151056-b3ae5175dc9b/go.mod h1:Tw/DK06oyO+lFvAQxmNPzXRlSWGk9vZlS2eNx4riAHo= +github.com/snapcore/secboot v0.0.0-20250124132100-452552189677 h1:B2Bf7T1aBXOgkwAEFnR/g8d2l9hjrzS/X6BsnVrBNI4= +github.com/snapcore/secboot v0.0.0-20250124132100-452552189677/go.mod h1:2cqUsx8AzOpyo7IAkeAln8SEr9ymC/GVOrFEYNL0RrI= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -67,13 +67,13 @@ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= diff --git a/overlord/devicestate/devicestate_install_mode_test.go b/overlord/devicestate/devicestate_install_mode_test.go index d2a0a1d3416..afe5b6942f0 100644 --- a/overlord/devicestate/devicestate_install_mode_test.go +++ b/overlord/devicestate/devicestate_install_mode_test.go @@ -2345,18 +2345,26 @@ func (s *deviceMgrInstallModeSuite) doRunFactoryResetChange(c *C, model *asserts return fmt.Errorf("unexpected call") })() - defer devicestate.MockSecbootRenameOrDeleteKeys(func(node string, renames map[string]string) error { + defer devicestate.MockSecbootRenameKeys(func(node string, renames map[string]string) error { if tc.encrypt { c.Check(node, Equals, "/dev/disk/by-uuid/570faa3d-e3bc-49db-979b-e7814b6bd390") c.Check(renames, DeepEquals, map[string]string{ - "default": "factory-reset-old", - "default-fallback": "factory-reset-old-fallback", + "default": "reprovision-default", + "default-fallback": "reprovision-default-fallback", }) return nil } c.Errorf("unexpected call") return fmt.Errorf("unexpected call") })() + defer devicestate.MockSecbootTemporaryNameOldKeys(func(devicePath string) error { + if tc.encrypt { + c.Check(devicePath, Equals, "/dev/disk/by-uuid/570faa3d-e3bc-49db-979b-e7814b6bd390") + return nil + } + c.Errorf("unexpected call") + return fmt.Errorf("unexpected call") + })() var bootstrapContainer *secboot.MockBootstrappedContainer defer devicestate.MockSecbootCreateBootstrappedContainer(func(key secboot.DiskUnlockKey, devicePath string) secboot.BootstrappedContainer { @@ -2705,6 +2713,18 @@ echo "mock output of: $(basename "$0") $*" "ID_FS_UUID": "570faa3d-e3bc-49db-979b-e7814b6bd390", }, nil })() + defer devicestate.MockSecbootRenameKeys(func(node string, renames map[string]string) error { + c.Check(node, Equals, "foo") + c.Check(renames, DeepEquals, map[string]string{ + "default": "reprovision-default", + "default-fallback": "reprovision-default-fallback", + }) + return nil + })() + defer devicestate.MockSecbootTemporaryNameOldKeys(func(devicePath string) error { + c.Check(devicePath, Equals, "/dev/disk/by-uuid/FOOUUID") + return nil + })() err = s.doRunFactoryResetChange(c, model, resetTestCase{ tpm: true, encrypt: true, trustedBootloader: true, @@ -2787,6 +2807,18 @@ echo "mock output of: $(basename "$0") $*" "ID_FS_UUID": "570faa3d-e3bc-49db-979b-e7814b6bd390", }, nil })() + defer devicestate.MockSecbootRenameKeys(func(node string, renames map[string]string) error { + c.Check(node, Equals, "foo") + c.Check(renames, DeepEquals, map[string]string{ + "default": "reprovision-default", + "default-fallback": "reprovision-default-fallback", + }) + return nil + })() + defer devicestate.MockSecbootTemporaryNameOldKeys(func(devicePath string) error { + c.Check(devicePath, Equals, "/dev/disk/by-uuid/FOOUUID") + return nil + })() err = s.doRunFactoryResetChange(c, model, resetTestCase{ tpm: true, encrypt: true, trustedBootloader: true, diff --git a/overlord/devicestate/devicestate_test.go b/overlord/devicestate/devicestate_test.go index c0637a37e8b..c06c6f01087 100644 --- a/overlord/devicestate/devicestate_test.go +++ b/overlord/devicestate/devicestate_test.go @@ -2250,7 +2250,7 @@ func (s *deviceMgrSuite) TestDeviceManagerEnsurePostFactoryResetEncrypted(c *C) c.Check(hintExpectFDEHook, Equals, false) c.Check(node, Equals, "/dev/disk/by-uuid/FOOUUID") c.Check(possibleOldKeys, DeepEquals, map[string]bool{ - "factory-reset-old-fallback": true, + "reprovision-default-fallback": true, }) switch removedOldHandles { case 1: @@ -2271,18 +2271,27 @@ func (s *deviceMgrSuite) TestDeviceManagerEnsurePostFactoryResetEncrypted(c *C) restore = devicestate.MockSecbootDeleteKeys(func(node string, matches map[string]bool) error { c.Check(node, Equals, "/dev/disk/by-uuid/FOOUUID") c.Check(matches, DeepEquals, map[string]bool{ - "factory-reset-old": true, - "factory-reset-old-fallback": true, + "reprovision-default": true, + "reprovision-default-fallback": true, }) deleteOldSaveKey++ return nil }) defer restore() + removeOldDiskKeys := 0 + restore = devicestate.MockSecbootDeleteOldKeys(func(devicePath string) error { + c.Check(devicePath, Equals, "/dev/disk/by-uuid/FOOUUID") + removeOldDiskKeys++ + return nil + }) + defer restore() + err = s.mgr.Ensure() c.Assert(err, IsNil) c.Check(transitionCalls, Equals, 0) c.Check(deleteOldSaveKey, Equals, 1) + c.Check(removeOldDiskKeys, Equals, 1) // factory reset marker is gone, the key was verified successfully c.Check(filepath.Join(dirs.SnapDeviceDir, "factory-reset"), testutil.FileAbsent) c.Check(filepath.Join(dirs.SnapFDEDir, "marker"), testutil.FilePresent) @@ -2290,6 +2299,7 @@ func (s *deviceMgrSuite) TestDeviceManagerEnsurePostFactoryResetEncrypted(c *C) transitionCalls = 0 deleteOldSaveKey = 0 + removeOldDiskKeys = 0 // try again, no marker, nothing should happen devicestate.SetPostFactoryResetRan(s.mgr, false) err = s.mgr.Ensure() @@ -2298,6 +2308,7 @@ func (s *deviceMgrSuite) TestDeviceManagerEnsurePostFactoryResetEncrypted(c *C) c.Check(transitionCalls, Equals, 0) c.Check(deleteOldSaveKey, Equals, 0) c.Check(removedOldHandles, Equals, 1) + c.Check(removeOldDiskKeys, Equals, 0) // have the marker, but keep the keys rotated as if boot code would do it and // try again, in this setup the marker hash matches the migrated key @@ -2309,6 +2320,7 @@ func (s *deviceMgrSuite) TestDeviceManagerEnsurePostFactoryResetEncrypted(c *C) c.Check(transitionCalls, Equals, 0) c.Check(deleteOldSaveKey, Equals, 1) c.Check(removedOldHandles, Equals, 2) + c.Check(removeOldDiskKeys, Equals, 1) // the marker was again removed c.Check(filepath.Join(dirs.SnapDeviceDir, "factory-reset"), testutil.FileAbsent) } diff --git a/overlord/devicestate/export_test.go b/overlord/devicestate/export_test.go index 77feebebd3e..84175aa04cf 100644 --- a/overlord/devicestate/export_test.go +++ b/overlord/devicestate/export_test.go @@ -619,11 +619,11 @@ func MockSecbootAddBootstrapKeyOnExistingDisk(f func(node string, newKey keys.En } } -func MockSecbootRenameOrDeleteKeys(f func(node string, renames map[string]string) error) (restore func()) { - old := secbootRenameOrDeleteKeys - secbootRenameOrDeleteKeys = f +func MockSecbootRenameKeys(f func(node string, renames map[string]string) error) (restore func()) { + old := secbootRenameKeys + secbootRenameKeys = f return func() { - secbootRenameOrDeleteKeys = old + secbootRenameKeys = old } } @@ -643,6 +643,22 @@ func MockSecbootDeleteKeys(f func(node string, matches map[string]bool) error) ( } } +func MockSecbootDeleteOldKeys(f func(devicePath string) error) (restore func()) { + old := secbootDeleteOldKeys + secbootDeleteOldKeys = f + return func() { + secbootDeleteOldKeys = old + } +} + +func MockSecbootTemporaryNameOldKeys(f func(devicePath string) error) (restore func()) { + old := secbootTemporaryNameOldKeys + secbootTemporaryNameOldKeys = f + return func() { + secbootTemporaryNameOldKeys = old + } +} + func MockDisksDMCryptUUIDFromMountPoint(f func(mountpoint string) (string, error)) (restore func()) { old := disksDMCryptUUIDFromMountPoint disksDMCryptUUIDFromMountPoint = f diff --git a/overlord/devicestate/handlers_install.go b/overlord/devicestate/handlers_install.go index e6d422c1d57..1b7275c80cd 100644 --- a/overlord/devicestate/handlers_install.go +++ b/overlord/devicestate/handlers_install.go @@ -78,6 +78,7 @@ var ( secbootStageEncryptionKeyChange = secboot.StageEncryptionKeyChange secbootTransitionEncryptionKeyChange = secboot.TransitionEncryptionKeyChange secbootRemoveOldCounterHandles = secboot.RemoveOldCounterHandles + secbootTemporaryNameOldKeys = secboot.TemporaryNameOldKeys installLogicPrepareRunSystemData = installLogic.PrepareRunSystemData ) @@ -1320,9 +1321,10 @@ func (m *DeviceManager) doInstallSetupStorageEncryption(t *state.Task, _ *tomb.T var ( secbootAddBootstrapKeyOnExistingDisk = secboot.AddBootstrapKeyOnExistingDisk - secbootRenameOrDeleteKeys = secboot.RenameOrDeleteKeys + secbootRenameKeys = secboot.RenameKeys secbootCreateBootstrappedContainer = secboot.CreateBootstrappedContainer secbootDeleteKeys = secboot.DeleteKeys + secbootDeleteOldKeys = secboot.DeleteOldKeys ) func createSaveBootstrappedContainer(saveNode string) (secboot.BootstrappedContainer, error) { @@ -1355,12 +1357,23 @@ func createSaveBootstrappedContainer(saveNode string) (secboot.BootstrappedConta // FIXME: Do we maybe need to only save the default-fallback // key and delete the default key? The default key will not be // able to be used since we re created the data disk. + // + // FIXME: The keys should be renamed to reprovision-XX and keep + // track of the mapping XX to original key name. renames := map[string]string{ - "default": "factory-reset-old", - "default-fallback": "factory-reset-old-fallback", + "default": "reprovision-default", + "default-fallback": "reprovision-default-fallback", } - if err := secbootRenameOrDeleteKeys(saveNode, renames); err != nil { - return nil, err + // Temporarily rename keyslots across the factory reset to + // allow to create the new ones. + if err := secbootRenameKeys(saveNode, renames); err != nil { + return nil, fmt.Errorf("cannot rename existing keys: %w", err) + } + + // Deal as needed instead with naming unamed keyslots, they + // will be removed at the end of factory reset. + if err := secbootTemporaryNameOldKeys(saveNode); err != nil { + return nil, fmt.Errorf("cannot convert old keys: %w", err) } return secbootCreateBootstrappedContainer(secboot.DiskUnlockKey(saveEncryptionKey), saveNode), nil @@ -1389,7 +1402,7 @@ func rotateSaveKeyAndDeleteOldKeys(saveMntPnt string) error { diskPath := filepath.Join("/dev/disk/by-uuid", uuid) oldPossiblyTPMKeySlots := map[string]bool{ - "factory-reset-old-fallback": true, + "reprovision-default-fallback": true, } defaultSaveKey := device.FallbackSaveSealedKeyUnder(boot.InitramfsSeedEncryptionKeyDir) @@ -1422,9 +1435,20 @@ func rotateSaveKeyAndDeleteOldKeys(saveMntPnt string) error { } oldKeySlots := map[string]bool{ - "factory-reset-old": true, - "factory-reset-old-fallback": true, + "reprovision-default": true, + "reprovision-default-fallback": true, } - return secbootDeleteKeys(diskPath, oldKeySlots) + // DeleteKeys will remove the keys that were renamed from the + // previous installation + if err := secbootDeleteKeys(diskPath, oldKeySlots); err != nil { + return fmt.Errorf("cannot delete previous keys: %w", err) + } + // DeleteOldKeys will remove the keys that were named by + // TemporaryNameOldKeys from an old disk that did not have names on + // keys. + if err := secbootDeleteOldKeys(diskPath); err != nil { + return fmt.Errorf("cannot remove old disk keys: %w", err) + } + return nil } diff --git a/secboot/export_sb_test.go b/secboot/export_sb_test.go index 0bb5a680fd6..9700dbc3b0e 100644 --- a/secboot/export_sb_test.go +++ b/secboot/export_sb_test.go @@ -330,6 +330,14 @@ func MockRenameLUKS2ContainerKey(f func(devicePath, keyslotName, renameTo string } } +func MockCopyAndRemoveLUKS2ContainerKey(f func(devicePath, keyslotName, renameTo string) error) (restore func()) { + old := sbCopyAndRemoveLUKS2ContainerKey + sbCopyAndRemoveLUKS2ContainerKey = f + return func() { + sbCopyAndRemoveLUKS2ContainerKey = old + } +} + func MockSbNewFileKeyDataReader(f func(path string) (*sb.FileKeyDataReader, error)) (restore func()) { old := sbNewFileKeyDataReader sbNewFileKeyDataReader = f diff --git a/secboot/secboot_dummy.go b/secboot/secboot_dummy.go index d70faa36e0f..8e334a5554a 100644 --- a/secboot/secboot_dummy.go +++ b/secboot/secboot_dummy.go @@ -71,7 +71,7 @@ func AddBootstrapKeyOnExistingDisk(node string, newKey keys.EncryptionKey) error return errBuildWithoutSecboot } -func RenameOrDeleteKeys(node string, renames map[string]string) error { +func RenameKeys(node string, renames map[string]string) error { return errBuildWithoutSecboot } @@ -105,6 +105,7 @@ func (ha *HashAlg) UnmarshalJSON([]byte) error { return errBuildWithoutSecboot } + func FindFreeHandle() (uint32, error) { return 0, errBuildWithoutSecboot } @@ -116,3 +117,11 @@ func GetPCRHandle(node, keySlot, keyFile string) (uint32, error) { func RemoveOldCounterHandles(node string, possibleOldKeys map[string]bool, possibleKeyFiles []string, hintExpectFDEHook bool) error { return errBuildWithoutSecboot } + +func TemporaryNameOldKeys(devicePath string) error { + return errBuildWithoutSecboot +} + +func DeleteOldKeys(devicePath string) error { + return errBuildWithoutSecboot +} diff --git a/secboot/secboot_sb.go b/secboot/secboot_sb.go index efdfbe317e6..b0463f4a88d 100644 --- a/secboot/secboot_sb.go +++ b/secboot/secboot_sb.go @@ -351,7 +351,10 @@ func AddBootstrapKeyOnExistingDisk(node string, newKey keys.EncryptionKey) error // Rename key slots on LUKS2 container. If the key slot does not // exist, it is ignored. If cryptsetup does not support renaming, then // the key slots are instead removed. -func RenameOrDeleteKeys(node string, renames map[string]string) error { +// WARNING: this function is not always atomic. If cryptsetup is too +// old, it will try to copy and delete keys instead. Please avoid +// using this function in new code. +func RenameKeys(node string, renames map[string]string) error { targets := make(map[string]bool) for _, renameTo := range renames { @@ -381,8 +384,8 @@ func RenameOrDeleteKeys(node string, renames map[string]string) error { if found { if err := sbRenameLUKS2ContainerKey(node, slot, renameTo); err != nil { if errors.Is(err, sb.ErrMissingCryptsetupFeature) { - if err := sbDeleteLUKS2ContainerKey(node, slot); err != nil { - return fmt.Errorf("cannot remove old container key: %v", err) + if err := sbCopyAndRemoveLUKS2ContainerKey(node, slot, renameTo); err != nil { + return fmt.Errorf("cannot rename old container key: %v", err) } } else { return fmt.Errorf("cannot rename container key: %v", err) @@ -492,3 +495,37 @@ func (key *SealKeyRequest) getWriter() (sb.KeyDataWriter, error) { return key.BootstrappedContainer.GetTokenWriter(key.SlotName) } } + +// TemporaryNameOldKeys takes a disk using legacy keyslots 0, 1, 2 and +// adds names to those keyslots. This is needed to convert the save +// disk during a factory reset. This is a no-operation if all keyslots +// are already named. +func TemporaryNameOldKeys(devicePath string) error { + if err := sb.NameLegacyLUKS2ContainerKey(devicePath, 0, "old-default-key"); err != nil && !errors.Is(err, sb.KeyslotAlreadyHasANameErr) { + return err + } + if err := sb.NameLegacyLUKS2ContainerKey(devicePath, 1, "old-recovery-key"); err != nil && !errors.Is(err, sb.KeyslotAlreadyHasANameErr) { + return err + } + if err := sb.NameLegacyLUKS2ContainerKey(devicePath, 2, "old-temporary-key"); err != nil && !errors.Is(err, sb.KeyslotAlreadyHasANameErr) { + return err + } + return nil +} + +// DeleteOldKeys removes key slots from an old installation that +// had names created by TemporaryNameOldKeys. +func DeleteOldKeys(devicePath string) error { + toDelete := map[string]bool{ + "old-default-key": true, + "old-recovery-key": true, + "old-temporary-key": true, + } + return DeleteKeys(devicePath, toDelete) +} + +func sbCopyAndRemoveLUKS2ContainerKeyImpl(devicePath, keyslotName, renameTo string) error { + return sb.CopyAndRemoveLUKS2ContainerKey(sb.AllowNonAtomicOperation(), devicePath, keyslotName, renameTo) +} + +var sbCopyAndRemoveLUKS2ContainerKey = sbCopyAndRemoveLUKS2ContainerKeyImpl diff --git a/secboot/secboot_sb_test.go b/secboot/secboot_sb_test.go index 436d5a6959f..282665424f9 100644 --- a/secboot/secboot_sb_test.go +++ b/secboot/secboot_sb_test.go @@ -2471,7 +2471,7 @@ func (s *secbootSuite) TestAddBootstrapKeyOnExistingDiskLUKS2Error(c *C) { c.Check(err, ErrorMatches, `cannot enroll new installation key: some error`) } -func (s *secbootSuite) TestRenameOrDeleteKeys(c *C) { +func (s *secbootSuite) TestRenameKeys(c *C) { defer secboot.MockListLUKS2ContainerUnlockKeyNames(func(devicePath string) ([]string, error) { c.Check(devicePath, Equals, "/dev/foo") return []string{"slot-a", "slot-b", "slot-c"}, nil @@ -2497,13 +2497,13 @@ func (s *secbootSuite) TestRenameOrDeleteKeys(c *C) { "slot-d": "new-slot-d", } - err := secboot.RenameOrDeleteKeys("/dev/foo", toRename) + err := secboot.RenameKeys("/dev/foo", toRename) c.Assert(err, IsNil) c.Check(expectedRenames, HasLen, 0) } -func (s *secbootSuite) TestRenameOrDeleteKeysBadInput(c *C) { +func (s *secbootSuite) TestRenameKeysBadInput(c *C) { defer secboot.MockListLUKS2ContainerUnlockKeyNames(func(devicePath string) ([]string, error) { c.Errorf("unexpected call") return []string{"slot-a", "slot-b", "slot-c"}, nil @@ -2519,11 +2519,11 @@ func (s *secbootSuite) TestRenameOrDeleteKeysBadInput(c *C) { "slot-b": "slot-c", } - err := secboot.RenameOrDeleteKeys("/dev/foo", toRename) + err := secboot.RenameKeys("/dev/foo", toRename) c.Assert(err, ErrorMatches, `internal error: keyslot name slot-b used as source and target of a rename`) } -func (s *secbootSuite) TestRenameOrDeleteKeysNameExists(c *C) { +func (s *secbootSuite) TestRenameKeysNameExists(c *C) { defer secboot.MockListLUKS2ContainerUnlockKeyNames(func(devicePath string) ([]string, error) { c.Check(devicePath, Equals, "/dev/foo") return []string{"slot-a", "slot-b", "slot-c"}, nil @@ -2538,19 +2538,19 @@ func (s *secbootSuite) TestRenameOrDeleteKeysNameExists(c *C) { "slot-a": "slot-b", } - err := secboot.RenameOrDeleteKeys("/dev/foo", toRename) + err := secboot.RenameKeys("/dev/foo", toRename) c.Assert(err, ErrorMatches, `slot name slot-b is already in use`) } -func (s *secbootSuite) TestRenameOrDeleteKeysNoRename(c *C) { +func (s *secbootSuite) TestRenameKeysNoRename(c *C) { defer secboot.MockListLUKS2ContainerUnlockKeyNames(func(devicePath string) ([]string, error) { c.Check(devicePath, Equals, "/dev/foo") return []string{"slot-a", "slot-b", "slot-c"}, nil })() - expectedRemovals := map[string]bool{ - "slot-b": true, - "slot-c": true, + expectedRenames := map[string]string{ + "slot-b": "new-slot-b", + "slot-c": "new-slot-c", } defer secboot.MockRenameLUKS2ContainerKey(func(devicePath, slotName, renameTo string) error { @@ -2558,11 +2558,12 @@ func (s *secbootSuite) TestRenameOrDeleteKeysNoRename(c *C) { return sb.ErrMissingCryptsetupFeature })() - defer secboot.MockDeleteLUKS2ContainerKey(func(devicePath, slotName string) error { + defer secboot.MockCopyAndRemoveLUKS2ContainerKey(func(devicePath, slotName, renameTo string) error { c.Check(devicePath, Equals, "/dev/foo") - _, expected := expectedRemovals[slotName] - c.Check(expected, Equals, true) - delete(expectedRemovals, slotName) + expectedRename, expected := expectedRenames[slotName] + c.Assert(expected, Equals, true) + c.Check(renameTo, Equals, expectedRename) + delete(expectedRenames, slotName) return nil })() @@ -2572,13 +2573,13 @@ func (s *secbootSuite) TestRenameOrDeleteKeysNoRename(c *C) { "slot-d": "new-slot-d", } - err := secboot.RenameOrDeleteKeys("/dev/foo", toRename) + err := secboot.RenameKeys("/dev/foo", toRename) c.Assert(err, IsNil) - c.Check(expectedRemovals, HasLen, 0) + c.Check(expectedRenames, HasLen, 0) } -func (s *secbootSuite) TestRenameOrDeleteKeysListError(c *C) { +func (s *secbootSuite) TestRenameKeysListError(c *C) { defer secboot.MockListLUKS2ContainerUnlockKeyNames(func(devicePath string) ([]string, error) { c.Check(devicePath, Equals, "/dev/foo") return nil, fmt.Errorf("some error") @@ -2600,11 +2601,11 @@ func (s *secbootSuite) TestRenameOrDeleteKeysListError(c *C) { "slot-d": "new-slot-d", } - err := secboot.RenameOrDeleteKeys("/dev/foo", toRename) + err := secboot.RenameKeys("/dev/foo", toRename) c.Assert(err, ErrorMatches, `cannot list slots in partition save partition: some error`) } -func (s *secbootSuite) TestRenameOrDeleteKeysRenameError(c *C) { +func (s *secbootSuite) TestRenameKeysRenameError(c *C) { defer secboot.MockListLUKS2ContainerUnlockKeyNames(func(devicePath string) ([]string, error) { c.Check(devicePath, Equals, "/dev/foo") return []string{"slot-a", "slot-b", "slot-c"}, nil @@ -2614,7 +2615,7 @@ func (s *secbootSuite) TestRenameOrDeleteKeysRenameError(c *C) { return fmt.Errorf("some other error") })() - defer secboot.MockDeleteLUKS2ContainerKey(func(devicePath, slotName string) error { + defer secboot.MockCopyAndRemoveLUKS2ContainerKey(func(devicePath, slotName, renameTo string) error { c.Errorf("unexpected call") return nil })() @@ -2625,11 +2626,11 @@ func (s *secbootSuite) TestRenameOrDeleteKeysRenameError(c *C) { "slot-d": "new-slot-d", } - err := secboot.RenameOrDeleteKeys("/dev/foo", toRename) + err := secboot.RenameKeys("/dev/foo", toRename) c.Assert(err, ErrorMatches, `cannot rename container key: some other error`) } -func (s *secbootSuite) TestRenameOrDeleteKeysDeleteError(c *C) { +func (s *secbootSuite) TestRenameKeysDeleteError(c *C) { defer secboot.MockListLUKS2ContainerUnlockKeyNames(func(devicePath string) ([]string, error) { c.Check(devicePath, Equals, "/dev/foo") return []string{"slot-a", "slot-b", "slot-c"}, nil @@ -2639,7 +2640,7 @@ func (s *secbootSuite) TestRenameOrDeleteKeysDeleteError(c *C) { return sb.ErrMissingCryptsetupFeature })() - defer secboot.MockDeleteLUKS2ContainerKey(func(devicePath, slotName string) error { + defer secboot.MockCopyAndRemoveLUKS2ContainerKey(func(devicePath, slotName, renameTo string) error { return fmt.Errorf("some error") })() @@ -2649,8 +2650,8 @@ func (s *secbootSuite) TestRenameOrDeleteKeysDeleteError(c *C) { "slot-d": "new-slot-d", } - err := secboot.RenameOrDeleteKeys("/dev/foo", toRename) - c.Assert(err, ErrorMatches, `cannot remove old container key: some error`) + err := secboot.RenameKeys("/dev/foo", toRename) + c.Assert(err, ErrorMatches, `cannot rename old container key: some error`) } func (s *secbootSuite) TestDeleteKeys(c *C) { diff --git a/secboot/secboot_tpm.go b/secboot/secboot_tpm.go index f78d7d6da03..48a65d71e62 100644 --- a/secboot/secboot_tpm.go +++ b/secboot/secboot_tpm.go @@ -814,7 +814,7 @@ func efiImageFromBootFile(b *bootloader.BootFile) (sb_efi.Image, error) { func tpmReleaseResourcesImpl(tpm *sb_tpm2.Connection, handle tpm2.Handle) error { rc, err := tpm.CreateResourceContextFromTPM(handle) if err != nil { - if _, ok := err.(tpm2.ResourceUnavailableError); ok { + if tpm2.IsResourceUnavailableError(err, handle) { // there's nothing to release, the handle isn't used return nil }