From 74675a725500784e971548c74a6ec44199946f94 Mon Sep 17 00:00:00 2001 From: Valentin David Date: Wed, 20 Nov 2024 17:21:22 +0100 Subject: [PATCH] crypt.go: allow adding names to legacy keyslots When reprovisioning with a newer snapd with old disks, we need to be able to convert old keyslots to new ones with names. Otherwise we cannot remove after reprovisioning is done. --- crypt.go | 31 ++++++++++++++++++++++++++++++ crypt_test.go | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/crypt.go b/crypt.go index dbe93974..e06a0518 100755 --- a/crypt.go +++ b/crypt.go @@ -934,3 +934,34 @@ func RenameLUKS2ContainerKey(devicePath, oldName, newName string) error { return nil } + +func NameLegacyLUKS2ContainerKey(devicePath string, keyslot int, newName string) error { + view, err := newLUKSView(devicePath, luks2.LockModeBlocking) + if err != nil { + return xerrors.Errorf("cannot obtain LUKS header view: %w", err) + } + + for _, name := range view.TokenNames() { + _, id, _ := view.TokenByName(name) + if keyslot == id { + return errors.New("keyslot already has a name") + } + } + + token := &luksview.KeyDataToken{ + TokenBase: luksview.TokenBase{ + TokenName: newName, + TokenKeyslot: keyslot, + }, + } + + if err := luks2ImportToken(devicePath, token, nil); err != nil { + return xerrors.Errorf("cannot import token: %w", err) + } + + if err := luks2SetSlotPriority(devicePath, keyslot, luks2.SlotPriorityHigh); err != nil { + return xerrors.Errorf("cannot change keyslot priority: %w", err) + } + + return nil +} diff --git a/crypt_test.go b/crypt_test.go index 5a2bc5af..5710d976 100644 --- a/crypt_test.go +++ b/crypt_test.go @@ -4003,3 +4003,55 @@ func (s *cryptSuite) TestActivateVolumeWithLegacyPathsError(c *C) { s.checkKeyDataKeysInKeyring(c, "", "/dev/some/path", unlockKey, primaryKey) } + +func (s *cryptSuite) TestNameLegacyLUKS2ContainerKey(c *C) { + firstKey := s.newPrimaryKey(c, 32) + secondKey := s.newPrimaryKey(c, 32) + + m := &mockLUKS2Container{ + tokens: map[int]luks2.Token{}, + keyslots: map[int][]byte{ + 0: firstKey, + 1: secondKey, + }, + } + + s.luks2.devices["/dev/foo1"] = m + + err := NameLegacyLUKS2ContainerKey("/dev/foo1", 0, "some-name") + c.Check(err, IsNil) + + token, hasToken := m.tokens[0] + c.Assert(hasToken, Equals, true) + c.Check(token, DeepEquals, &luksview.KeyDataToken{ + TokenBase: luksview.TokenBase{ + TokenKeyslot: 0, + TokenName: "some-name", + }, + }) +} + +func (s *cryptSuite) TestNameLegacyLUKS2ContainerKeyNameExists(c *C) { + firstKey := s.newPrimaryKey(c, 32) + secondKey := s.newPrimaryKey(c, 32) + + m := &mockLUKS2Container{ + tokens: map[int]luks2.Token{ + 1: &luksview.KeyDataToken{ + TokenBase: luksview.TokenBase{ + TokenKeyslot: 1, + TokenName: "already", + }, + }, + }, + keyslots: map[int][]byte{ + 0: firstKey, + 1: secondKey, + }, + } + + s.luks2.devices["/dev/foo1"] = m + + err := NameLegacyLUKS2ContainerKey("/dev/foo1", 1, "some-name") + c.Check(err, ErrorMatches, `keyslot already has a name`) +}