diff --git a/crypt.go b/crypt.go index 8c3699f1..6dd28ecf 100755 --- a/crypt.go +++ b/crypt.go @@ -45,6 +45,8 @@ var ( // required features. ErrMissingCryptsetupFeature = luks2.ErrMissingCryptsetupFeature + ErrKeyslotNameNotExist = errors.New("no key with the specified name exists") + luks2Activate = luks2.Activate luks2AddKey = luks2.AddKey luks2Deactivate = luks2.Deactivate @@ -870,7 +872,7 @@ func DeleteLUKS2ContainerKey(devicePath, keyslotName string) error { token, id, exists := view.TokenByName(keyslotName) if !exists { - return errors.New("no key with the specified name exists") + return ErrKeyslotNameNotExist } if len(view.TokenNames()) == 1 { @@ -920,7 +922,7 @@ func renameLUKS2ContainerKey(nonAtomic *nonAtomicOperationAllowedFlag, devicePat token, id, exists := view.TokenByName(oldName) if !exists { - return errors.New("no key with the specified name exists") + return ErrKeyslotNameNotExist } if _, _, exists := view.TokenByName(newName); exists { @@ -1044,3 +1046,20 @@ func NameLegacyLUKS2ContainerKey(devicePath string, keyslot int, newName string) func TestLUKS2ContainerKey(devicePath string, key []byte) bool { return luks2.TestContainerKey(devicePath, key) } + +// Check if key is valid key for LUKS2 container at devicePath for a specific keyslot. +func TestLUKS2ContainerKeyForKeyslot(devicePath string, name string, key []byte) (bool, error) { + view, err := newLUKSView(context.TODO(), devicePath) + if err != nil { + return false, xerrors.Errorf("cannot obtain LUKS header view: %w", err) + } + + token, _, exists := view.TokenByName(name) + if !exists { + return false, ErrKeyslotNameNotExist + } + + keyslotId := token.Keyslots()[0] + + return luks2.TestContainerKeyForKeyslot(devicePath, keyslotId, key), nil +} diff --git a/crypt_test.go b/crypt_test.go index ecb29361..98343a99 100644 --- a/crypt_test.go +++ b/crypt_test.go @@ -4137,3 +4137,41 @@ func (s *cryptSuite) TestNameLegacyLUKS2ContainerKeyNameAlreadyUsed(c *C) { err := NameLegacyLUKS2ContainerKey("/dev/foo1", 0, "already-used") c.Check(err, ErrorMatches, `the new name is already in use`) } + +func (s *cryptSuiteUnmockedBase) TestTestLUKS2ContainerKeyForKeyslot(c *C) { + key := s.newPrimaryKey() + path := luks2test.CreateEmptyDiskImage(c, 20) + + initOptions := &InitializeLUKS2ContainerOptions{ + InitialKeyslotName: "initial", + } + c.Assert(InitializeLUKS2Container(path, "disk", key, initOptions), IsNil) + + otherKey := s.newPrimaryKey() + c.Assert(AddLUKS2ContainerUnlockKey(path, "other", key, otherKey), IsNil) + + recoveryKey := s.newRecoveryKey() + c.Assert(AddLUKS2ContainerRecoveryKey(path, "recovery", key, recoveryKey), IsNil) + + check := func(name string, testKey []byte, expected bool) { + res, err := TestLUKS2ContainerKeyForKeyslot(path, name, testKey) + c.Assert(err, IsNil) + c.Check(res, Equals, expected) + } + + check("initial", key, true) + check("initial", otherKey, false) + check("initial", recoveryKey[:], false) + + check("other", key, false) + check("other", otherKey, true) + check("other", recoveryKey[:], false) + + check("recovery", key, false) + check("recovery", otherKey, false) + check("recovery", recoveryKey[:], true) + + _, err := TestLUKS2ContainerKeyForKeyslot(path, "non-existent", key) + c.Check(err, ErrorMatches, `no key with the specified name exists`) + c.Check(errors.Is(err, ErrKeyslotNameNotExist), Equals, true) +} diff --git a/internal/luks2/cryptsetup.go b/internal/luks2/cryptsetup.go index 745ff80b..2cd2f37a 100755 --- a/internal/luks2/cryptsetup.go +++ b/internal/luks2/cryptsetup.go @@ -506,3 +506,8 @@ func SetSlotPriority(devicePath string, slot int, priority SlotPriority) error { func TestContainerKey(devicePath string, key []byte) bool { return cryptsetupCmd(bytes.NewReader(key), "open", "--test-passphrase", "--key-file", "-", devicePath) == nil } + +// Check if key is valid key for LUKS2 container at devicePath for a specific keyslot. +func TestContainerKeyForKeyslot(devicePath string, slot int, key []byte) bool { + return cryptsetupCmd(bytes.NewReader(key), "open", "--test-passphrase", "--key-slot", strconv.Itoa(slot), "--key-file", "-", devicePath) == nil +} diff --git a/internal/luks2/cryptsetup_test.go b/internal/luks2/cryptsetup_test.go index 9546f68e..15666f4b 100644 --- a/internal/luks2/cryptsetup_test.go +++ b/internal/luks2/cryptsetup_test.go @@ -1339,3 +1339,20 @@ func (s *cipherSuite) TestSelectCipherAndKeysize(c *C) { c.Check(keysize, Equals, tc.expectedKeysize) } } + +func (s *cryptsetupSuite) TestTestContainerKeyForKeyslot(c *C) { + key := make([]byte, 32) + rand.Read(key) + + otherKey := make([]byte, 32) + rand.Read(otherKey) + + devicePath := luks2test.CreateEmptyDiskImage(c, 20) + c.Assert(Format(devicePath, "test", key, &FormatOptions{}), IsNil) + c.Assert(AddKey(devicePath, key, otherKey, &AddKeyOptions{Slot: 1}), IsNil) + + c.Check(TestContainerKeyForKeyslot(devicePath, 0, key), Equals, true) + c.Check(TestContainerKeyForKeyslot(devicePath, 0, otherKey), Equals, false) + c.Check(TestContainerKeyForKeyslot(devicePath, 1, key), Equals, false) + c.Check(TestContainerKeyForKeyslot(devicePath, 1, otherKey), Equals, true) +}