From b0bd57d4a1becc5236bef4851afd728af569938e Mon Sep 17 00:00:00 2001 From: Valentin David Date: Fri, 20 Sep 2024 11:09:51 +0200 Subject: [PATCH] overload/fdestate/backend: implement FDE hook resealing --- overlord/fdestate/backend/reseal.go | 55 ++++++++++++++++++++++++++++- secboot/secboot_hooks.go | 31 ++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/overlord/fdestate/backend/reseal.go b/overlord/fdestate/backend/reseal.go index 7387d9acfb7..1e9bd62a819 100644 --- a/overlord/fdestate/backend/reseal.go +++ b/overlord/fdestate/backend/reseal.go @@ -24,6 +24,7 @@ import ( "fmt" "path/filepath" + "github.com/snapcore/snapd/asserts" "github.com/snapcore/snapd/boot" "github.com/snapcore/snapd/bootloader" "github.com/snapcore/snapd/dirs" @@ -48,12 +49,64 @@ func MockSecbootResealKeys(f func(params *secboot.ResealKeysParams) error) (rest } } +type comparableModel struct { + BrandID string + SignKeyID string + Model string + Classic bool + Grade asserts.ModelGrade + Series string +} + +func toComparable(m secboot.ModelForSealing) comparableModel { + return comparableModel{ + BrandID: m.BrandID(), + SignKeyID: m.SignKeyID(), + Model: m.Model(), + Classic: m.Classic(), + Grade: m.Grade(), + Series: m.Series(), + } +} + +func resealKeyForBootChainsFDEHook(method device.SealingMethod, rootdir string, params *boot.ResealKeyForBootChainsParams, expectReseal bool) error { + uniqueModels := make(map[comparableModel]secboot.ModelForSealing) + + for _, bc := range params.RunModeBootChains { + m := bc.ModelForSealing() + uniqueModels[toComparable(m)] = m + } + for _, bc := range params.RecoveryBootChainsForRunKey { + m := bc.ModelForSealing() + uniqueModels[toComparable(m)] = m + } + for _, bc := range params.RecoveryBootChains { + m := bc.ModelForSealing() + uniqueModels[toComparable(m)] = m + } + + var models []secboot.ModelForSealing + for _, m := range uniqueModels { + models = append(models, m) + } + + keys := []string{ + device.DataSealedKeyUnder(boot.InitramfsBootEncryptionKeyDir), + device.FallbackDataSealedKeyUnder(boot.InitramfsSeedEncryptionKeyDir), + device.FallbackSaveSealedKeyUnder(boot.InitramfsSeedEncryptionKeyDir), + } + + primaryKey := filepath.Join(boot.InstallHostFDESaveDir, "aux-key") + + return secboot.ResealKeysWithFDESetupHook(keys, primaryKey, models) +} + // ResealKeyForBootChains reseals disk encryption keys with the given bootchains. func ResealKeyForBootChains(method device.SealingMethod, rootdir string, params *boot.ResealKeyForBootChainsParams, expectReseal bool) error { switch method { case device.SealingMethodFDESetupHook: // FIXME: do something - return nil + return resealKeyForBootChainsFDEHook(method, rootdir, params, expectReseal) case device.SealingMethodTPM, device.SealingMethodLegacyTPM: default: return fmt.Errorf("unknown key sealing method: %q", method) diff --git a/secboot/secboot_hooks.go b/secboot/secboot_hooks.go index 256668a379b..18641e88176 100644 --- a/secboot/secboot_hooks.go +++ b/secboot/secboot_hooks.go @@ -119,6 +119,37 @@ func SealKeysWithFDESetupHook(runHook fde.RunSetupHookFunc, keys []SealKeyReques return nil } +func ResealKeysWithFDESetupHook(keyFiles []string, primaryKeyFile string, models []ModelForSealing) error { + primaryKeyBuf, err := os.ReadFile(primaryKeyFile) + if err != nil { + return fmt.Errorf("cannot read primary key file: %v", err) + } + primaryKey := sb.PrimaryKey(primaryKeyBuf) + + var sbModels []sb.SnapModel + for _, model := range models { + sbModels = append(sbModels, model) + } + for _, keyFile := range keyFiles { + reader, err := sbNewFileKeyDataReader(keyFile) + if err != nil { + return fmt.Errorf("cannot open key data: %v", err) + } + keyData, err := sbReadKeyData(reader) + if err != nil { + return fmt.Errorf("cannot read key data: %v", err) + } + keyData.SetAuthorizedSnapModels(primaryKey, sbModels...) + + writer := sb.NewFileKeyDataWriter(keyFile) + if err := keyData.WriteAtomic(writer); err != nil { + return err + } + } + + return nil +} + func isV1EncryptedKeyFile(p string) bool { // XXX move some of this to kernel/fde var v1KeyPrefix = []byte("USK$")