2022-09-05 03:06:08 -04:00
|
|
|
/*
|
|
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
*/
|
|
|
|
|
2022-04-20 05:35:23 -04:00
|
|
|
package diskencryption
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"path"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/spf13/afero"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
2022-06-30 09:24:36 -04:00
|
|
|
"go.uber.org/goleak"
|
2022-04-20 05:35:23 -04:00
|
|
|
)
|
|
|
|
|
2022-06-30 09:24:36 -04:00
|
|
|
func TestMain(m *testing.M) {
|
|
|
|
goleak.VerifyTestMain(m)
|
|
|
|
}
|
|
|
|
|
2022-04-20 05:35:23 -04:00
|
|
|
func TestOpenClose(t *testing.T) {
|
|
|
|
testCases := map[string]struct {
|
|
|
|
initByNameErr error
|
|
|
|
operations []string
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr bool
|
2022-04-20 05:35:23 -04:00
|
|
|
}{
|
|
|
|
"open and close work": {
|
|
|
|
operations: []string{"open", "close"},
|
|
|
|
},
|
|
|
|
"opening twice fails": {
|
2022-04-26 10:54:05 -04:00
|
|
|
operations: []string{"open", "open"},
|
|
|
|
wantErr: true,
|
2022-04-20 05:35:23 -04:00
|
|
|
},
|
|
|
|
"closing first fails": {
|
2022-04-26 10:54:05 -04:00
|
|
|
operations: []string{"close"},
|
|
|
|
wantErr: true,
|
2022-04-20 05:35:23 -04:00
|
|
|
},
|
|
|
|
"initByName failure detected": {
|
|
|
|
initByNameErr: errors.New("initByNameErr"),
|
|
|
|
operations: []string{"open"},
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-04-20 05:35:23 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
require := require.New(t)
|
|
|
|
|
|
|
|
crypt := Cryptsetup{
|
|
|
|
fs: afero.NewMemMapFs(),
|
|
|
|
initByName: func(name string) (cryptdevice, error) {
|
|
|
|
return &stubCryptdevice{}, tc.initByNameErr
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
err := executeOperations(&crypt, tc.operations)
|
2022-04-26 10:54:05 -04:00
|
|
|
if tc.wantErr {
|
2022-04-20 05:35:23 -04:00
|
|
|
assert.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
require.NoError(err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUUID(t *testing.T) {
|
|
|
|
testCases := map[string]struct {
|
2022-04-26 10:54:05 -04:00
|
|
|
open bool
|
|
|
|
wantUUID string
|
|
|
|
wantErr bool
|
2022-04-20 05:35:23 -04:00
|
|
|
}{
|
|
|
|
"getting uuid works": {
|
2022-04-26 10:54:05 -04:00
|
|
|
open: true,
|
|
|
|
wantUUID: "uuid",
|
2022-04-20 05:35:23 -04:00
|
|
|
},
|
|
|
|
"getting uuid on closed device fails": {
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-04-20 05:35:23 -04:00
|
|
|
},
|
|
|
|
"empty uuid is detected": {
|
2022-04-26 10:54:05 -04:00
|
|
|
open: true,
|
|
|
|
wantErr: true,
|
2022-04-20 05:35:23 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
require := require.New(t)
|
|
|
|
|
|
|
|
crypt := Cryptsetup{
|
|
|
|
fs: afero.NewMemMapFs(),
|
|
|
|
initByName: func(name string) (cryptdevice, error) {
|
2022-04-26 10:54:05 -04:00
|
|
|
return &stubCryptdevice{uuid: tc.wantUUID}, nil
|
2022-04-20 05:35:23 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
if tc.open {
|
|
|
|
require.NoError(crypt.Open())
|
|
|
|
defer crypt.Close()
|
|
|
|
}
|
|
|
|
uuid, err := crypt.UUID()
|
2022-04-26 10:54:05 -04:00
|
|
|
if tc.wantErr {
|
2022-04-20 05:35:23 -04:00
|
|
|
assert.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
require.NoError(err)
|
2022-04-26 10:54:05 -04:00
|
|
|
assert.Equal(tc.wantUUID, uuid)
|
2022-04-20 05:35:23 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpdatePassphrase(t *testing.T) {
|
|
|
|
testCases := map[string]struct {
|
|
|
|
writePassphrase bool
|
|
|
|
open bool
|
|
|
|
keyslotChangeByPassphraseErr error
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr bool
|
2022-04-20 05:35:23 -04:00
|
|
|
}{
|
|
|
|
"updating passphrase works": {
|
|
|
|
writePassphrase: true,
|
|
|
|
open: true,
|
|
|
|
},
|
|
|
|
"updating passphrase on closed device fails": {
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-04-20 05:35:23 -04:00
|
|
|
},
|
|
|
|
"reading initial passphrase can fail": {
|
2022-04-26 10:54:05 -04:00
|
|
|
open: true,
|
|
|
|
wantErr: true,
|
2022-04-20 05:35:23 -04:00
|
|
|
},
|
|
|
|
"changing keyslot passphrase can fail": {
|
|
|
|
open: true,
|
|
|
|
writePassphrase: true,
|
|
|
|
keyslotChangeByPassphraseErr: errors.New("keyslotChangeByPassphraseErr"),
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-04-20 05:35:23 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
require := require.New(t)
|
|
|
|
|
|
|
|
fs := afero.NewMemMapFs()
|
|
|
|
if tc.writePassphrase {
|
|
|
|
require.NoError(fs.MkdirAll(path.Base(initialKeyPath), 0o777))
|
|
|
|
require.NoError(afero.WriteFile(fs, initialKeyPath, []byte("key"), 0o777))
|
|
|
|
}
|
|
|
|
|
|
|
|
crypt := Cryptsetup{
|
|
|
|
fs: fs,
|
|
|
|
initByName: func(name string) (cryptdevice, error) {
|
|
|
|
return &stubCryptdevice{keyslotChangeErr: tc.keyslotChangeByPassphraseErr}, nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
if tc.open {
|
|
|
|
require.NoError(crypt.Open())
|
|
|
|
defer crypt.Close()
|
|
|
|
}
|
|
|
|
err := crypt.UpdatePassphrase("new-key")
|
2022-04-26 10:54:05 -04:00
|
|
|
if tc.wantErr {
|
2022-04-20 05:35:23 -04:00
|
|
|
assert.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
require.NoError(err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func executeOperations(crypt *Cryptsetup, operations []string) error {
|
|
|
|
for _, operation := range operations {
|
|
|
|
var err error
|
|
|
|
switch operation {
|
|
|
|
case "open":
|
|
|
|
err = crypt.Open()
|
|
|
|
case "close":
|
|
|
|
err = crypt.Close()
|
|
|
|
default:
|
|
|
|
panic("unknown operation")
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type stubCryptdevice struct {
|
|
|
|
uuid string
|
|
|
|
keyslotChangeErr error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *stubCryptdevice) GetUUID() string {
|
|
|
|
return s.uuid
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *stubCryptdevice) KeyslotChangeByPassphrase(currentKeyslot int, newKeyslot int, currentPassphrase string, newPassphrase string) error {
|
|
|
|
return s.keyslotChangeErr
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *stubCryptdevice) Free() bool {
|
|
|
|
return false
|
|
|
|
}
|