Skip to content

Commit

Permalink
secboot,overlord/fdestate: seal with boot mode for FDE hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
valentindavid committed Feb 11, 2025
1 parent 429eb11 commit 8864d86
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 14 deletions.
2 changes: 1 addition & 1 deletion overlord/fdestate/backend/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
"github.com/snapcore/snapd/secboot"
)

func MockSecbootResealKeysWithFDESetupHook(f func(keys []secboot.KeyDataLocation, primaryKeyFile string, models []secboot.ModelForSealing) error) (restore func()) {
func MockSecbootResealKeysWithFDESetupHook(f func(keys []secboot.KeyDataLocation, primaryKeyFile string, models []secboot.ModelForSealing, bootModes []string) error) (restore func()) {
old := secbootResealKeysWithFDESetupHook
secbootResealKeysWithFDESetupHook = f
return func() {
Expand Down
4 changes: 2 additions & 2 deletions overlord/fdestate/backend/reseal.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,12 @@ func doReseal(manager FDEStateManager, method device.SealingMethod, rootdir stri
case device.SealingMethodFDESetupHook:
primaryKeyFile := filepath.Join(boot.InstallHostFDESaveDir, "aux-key")
if runParams != nil {
if err := secbootResealKeysWithFDESetupHook(runKeys, primaryKeyFile, runParams.Models); err != nil {
if err := secbootResealKeysWithFDESetupHook(runKeys, primaryKeyFile, runParams.Models, runParams.BootModes); err != nil {
return err
}
}
if recoveryParams != nil {
if err := secbootResealKeysWithFDESetupHook(recoveryKeys, primaryKeyFile, recoveryParams.Models); err != nil {
if err := secbootResealKeysWithFDESetupHook(recoveryKeys, primaryKeyFile, recoveryParams.Models, recoveryParams.BootModes); err != nil {
return err
}
}
Expand Down
2 changes: 1 addition & 1 deletion overlord/fdestate/backend/reseal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1793,7 +1793,7 @@ func (s *resealTestSuite) TestHooksResealHappy(c *C) {
}

resealCalls := 0
restore := fdeBackend.MockSecbootResealKeysWithFDESetupHook(func(keys []secboot.KeyDataLocation, primaryKeyFile string, models []secboot.ModelForSealing) error {
restore := fdeBackend.MockSecbootResealKeysWithFDESetupHook(func(keys []secboot.KeyDataLocation, primaryKeyFile string, models []secboot.ModelForSealing, bootModes []string) error {
resealCalls++

switch resealCalls {
Expand Down
5 changes: 5 additions & 0 deletions overlord/fdestate/backend/seal.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func runKeySealRequests(key secboot.BootstrappedContainer, useTokens bool) []sec
KeyName: "ubuntu-data",
SlotName: "default",
KeyFile: keyFile,
BootModes: []string{"run", "recover"},
},
}
}
Expand All @@ -83,12 +84,16 @@ func fallbackKeySealRequests(key, saveKey secboot.BootstrappedContainer, factory
KeyName: "ubuntu-data",
SlotName: "default-fallback",
KeyFile: dataFallbackKey,
// TODO:FDEM:FIX we should not not have "factory-reset" here, but for now
// we want to have the same as the pcr profile
BootModes: []string{"recover", "factory-reset"},
},
{
BootstrappedContainer: saveKey,
KeyName: "ubuntu-save",
SlotName: "default-fallback",
KeyFile: saveFallbackKey,
BootModes: []string{"recover", "factory-reset"},
},
}
}
Expand Down
6 changes: 3 additions & 3 deletions overlord/fdestate/backend/seal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func (s *sealSuite) TestSealKeyForBootChains(c *C) {
// the run object seals only the ubuntu-data key
c.Check(params.TPMPolicyAuthKeyFile, Equals, filepath.Join(boot.InstallHostFDESaveDir, "tpm-policy-auth-key"))

expectedSKR := secboot.SealKeyRequest{BootstrappedContainer: myKey, KeyName: "ubuntu-data", SlotName: "default"}
expectedSKR := secboot.SealKeyRequest{BootstrappedContainer: myKey, KeyName: "ubuntu-data", SlotName: "default", BootModes: []string{"run", "recover"}}
if tc.disableTokens {
expectedSKR.KeyFile = filepath.Join(rootdir, "run/mnt/ubuntu-boot/device/fde/ubuntu-data.sealed-key")
}
Expand All @@ -179,8 +179,8 @@ func (s *sealSuite) TestSealKeyForBootChains(c *C) {
// the fallback object seals the ubuntu-data and the ubuntu-save keys
c.Check(params.TPMPolicyAuthKeyFile, Equals, "")

expectedDataSKR := secboot.SealKeyRequest{BootstrappedContainer: myKey, KeyName: "ubuntu-data", SlotName: "default-fallback"}
expectedSaveSKR := secboot.SealKeyRequest{BootstrappedContainer: myKey2, KeyName: "ubuntu-save", SlotName: "default-fallback"}
expectedDataSKR := secboot.SealKeyRequest{BootstrappedContainer: myKey, KeyName: "ubuntu-data", SlotName: "default-fallback", BootModes: []string{"recover", "factory-reset"}}
expectedSaveSKR := secboot.SealKeyRequest{BootstrappedContainer: myKey2, KeyName: "ubuntu-save", SlotName: "default-fallback", BootModes: []string{"recover", "factory-reset"}}
if tc.disableTokens {
expectedDataSKR.KeyFile = filepath.Join(rootdir, "run/mnt/ubuntu-seed/device/fde/ubuntu-data.recovery.sealed-key")
if tc.factoryReset {
Expand Down
8 changes: 8 additions & 0 deletions secboot/export_sb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,14 @@ func MockSetAuthorizedSnapModelsOnHooksKeydata(f func(kd *sb_hooks.KeyData, rand
}
}

func MockSetAuthorizedBootModesOnHooksKeydata(f func(kd *sb_hooks.KeyData, rand io.Reader, key sb.PrimaryKey, bootModes ...string) error) (restore func()) {
old := setAuthorizedBootModesOnHooksKeydata
setAuthorizedBootModesOnHooksKeydata = f
return func() {
setAuthorizedBootModesOnHooksKeydata = old
}
}

type DefaultKeyLoader = defaultKeyLoader

var ReadKeyFile = readKeyFile
Expand Down
2 changes: 2 additions & 0 deletions secboot/secboot.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ type SealKeyRequest struct {
// The file to store the key data. If empty, the key data will
// be saved to the token.
KeyFile string
// The boot modes allow (i.e. snapd_recovery_mode kernel parameter)
BootModes []string
}

// ModelForSealing provides information about the model for use in the context
Expand Down
2 changes: 1 addition & 1 deletion secboot/secboot_dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func VerifyPrimaryKeyDigest(devicePath string, alg crypto.Hash, salt []byte, dig
return false, errBuildWithoutSecboot
}

func ResealKeysWithFDESetupHook(keys []KeyDataLocation, primaryKeyFile string, models []ModelForSealing) error {
func ResealKeysWithFDESetupHook(keys []KeyDataLocation, primaryKeyFile string, models []ModelForSealing, bootModes []string) error {
return errBuildWithoutSecboot
}

Expand Down
13 changes: 11 additions & 2 deletions secboot/secboot_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func SealKeysWithFDESetupHook(runHook fde.RunSetupHookFunc, keys []SealKeyReques
AuthorizedSnapModels: []sb.SnapModel{
params.Model,
},
// TODO:FDEM:FIX: add boot modes
AuthorizedBootModes: skr.BootModes,
}

protectedKey, primaryKeyOut, unlockKey, err := sb_hooks.NewProtectedKey(rand.Reader, params)
Expand Down Expand Up @@ -132,9 +132,15 @@ func setAuthorizedSnapModelsOnHooksKeydataImpl(kd *sb_hooks.KeyData, rand io.Rea

var setAuthorizedSnapModelsOnHooksKeydata = setAuthorizedSnapModelsOnHooksKeydataImpl

func setAuthorizedBootModesOnHooksKeydataImpl(kd *sb_hooks.KeyData, rand io.Reader, key sb.PrimaryKey, bootmodes ...string) error {
return kd.SetAuthorizedBootModes(rand, key, bootmodes...)
}

var setAuthorizedBootModesOnHooksKeydata = setAuthorizedBootModesOnHooksKeydataImpl

// ResealKeysWithFDESetupHook updates hook based keydatas for given
// files with a specific list of models
func ResealKeysWithFDESetupHook(keys []KeyDataLocation, primaryKeyFile string, models []ModelForSealing) error {
func ResealKeysWithFDESetupHook(keys []KeyDataLocation, primaryKeyFile string, models []ModelForSealing, bootModes []string) error {
// TODO:FDEM:FIX: load primary key from keyring when available
primaryKeyBuf, err := os.ReadFile(primaryKeyFile)
if err != nil {
Expand Down Expand Up @@ -187,6 +193,9 @@ func ResealKeysWithFDESetupHook(keys []KeyDataLocation, primaryKeyFile string, m
if err := setAuthorizedSnapModelsOnHooksKeydata(hooksKeyData, rand.Reader, primaryKey, sbModels...); err != nil {
return err
}
if err := setAuthorizedBootModesOnHooksKeydata(hooksKeyData, rand.Reader, primaryKey, bootModes...); err != nil {
return err
}
}

if err := keyData.WriteAtomic(keyDataWriter); err != nil {
Expand Down
26 changes: 22 additions & 4 deletions secboot/secboot_sb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2849,7 +2849,7 @@ func (s *secbootSuite) TestResealKeysWithFDESetupHookV1(c *C) {
KeyFile: key1Fn,
}

err = secboot.ResealKeysWithFDESetupHook([]secboot.KeyDataLocation{key1Location}, auxKeyFn, []secboot.ModelForSealing{m})
err = secboot.ResealKeysWithFDESetupHook([]secboot.KeyDataLocation{key1Location}, auxKeyFn, []secboot.ModelForSealing{m}, []string{"run"})
c.Assert(err, IsNil)

// Nothing should have happened. But we make sure that they key is still there untouched.
Expand Down Expand Up @@ -2890,7 +2890,7 @@ func (s *secbootSuite) TestResealKeysWithFDESetupHookV2(c *C) {
KeyFile: key1Fn,
}

err = secboot.ResealKeysWithFDESetupHook([]secboot.KeyDataLocation{key1Location}, auxKeyFn, []secboot.ModelForSealing{m})
err = secboot.ResealKeysWithFDESetupHook([]secboot.KeyDataLocation{key1Location}, auxKeyFn, []secboot.ModelForSealing{m}, []string{"run"})
c.Assert(err, IsNil)

afterReader, err := sb.NewFileKeyDataReader(key1Fn)
Expand Down Expand Up @@ -2965,15 +2965,24 @@ func (s *secbootSuite) TestResealKeysWithFDESetupHook(c *C) {
return nil
})

bootModesSet := 0
secboot.MockSetAuthorizedBootModesOnHooksKeydata(func(kd *sb_hooks.KeyData, rand io.Reader, key sb.PrimaryKey, bootModes ...string) error {
bootModesSet++
c.Check([]byte(key), DeepEquals, primaryKey)
c.Check(bootModes, DeepEquals, []string{"some-mode"})
return nil
})

key1Location := secboot.KeyDataLocation{
DevicePath: "/dev/somedevice",
SlotName: "token-name",
KeyFile: key1Fn,
}

err = secboot.ResealKeysWithFDESetupHook([]secboot.KeyDataLocation{key1Location}, primaryKeyFn, []secboot.ModelForSealing{newModel})
err = secboot.ResealKeysWithFDESetupHook([]secboot.KeyDataLocation{key1Location}, primaryKeyFn, []secboot.ModelForSealing{newModel}, []string{"some-mode"})
c.Assert(err, IsNil)
c.Check(modelSet, Equals, 1)
c.Check(bootModesSet, Equals, 1)
c.Check(tokenWritten, Equals, 1)
}

Expand Down Expand Up @@ -3030,15 +3039,24 @@ func (s *secbootSuite) TestResealKeysWithFDESetupHookFromFile(c *C) {
return nil
})

bootModesSet := 0
secboot.MockSetAuthorizedBootModesOnHooksKeydata(func(kd *sb_hooks.KeyData, rand io.Reader, key sb.PrimaryKey, bootModes ...string) error {
bootModesSet++
c.Check([]byte(key), DeepEquals, primaryKey)
c.Check(bootModes, DeepEquals, []string{"some-mode"})
return nil
})

key1Location := secboot.KeyDataLocation{
DevicePath: "/dev/foo",
SlotName: "default",
KeyFile: key1Fn,
}

err = secboot.ResealKeysWithFDESetupHook([]secboot.KeyDataLocation{key1Location}, primaryKeyFn, []secboot.ModelForSealing{newModel})
err = secboot.ResealKeysWithFDESetupHook([]secboot.KeyDataLocation{key1Location}, primaryKeyFn, []secboot.ModelForSealing{newModel}, []string{"some-mode"})
c.Assert(err, IsNil)
c.Check(modelSet, Equals, 1)
c.Check(bootModesSet, Equals, 1)
// We tried to read key data from token
c.Check(readKeyTokenCalls, Equals, 1)
}
Expand Down

0 comments on commit 8864d86

Please sign in to comment.