kairos-sdk/signatures/signatures_test.go
Itxaka a0c7d13520
Port signature utils to sdk from agent (#117)
It was added first to agent as it was needed for upgrade but if we are
gonna reuse this to check for signature validity in random files, we
better have it on sdk so we can use it both on agent and immucore and
works exactly the same

Signed-off-by: Itxaka <itxaka@kairos.io>
2024-06-04 08:31:00 +02:00

156 lines
6.4 KiB
Go

package signatures
import (
"bytes"
"fmt"
"os"
"path/filepath"
"testing"
"github.com/foxboron/go-uefi/efi/attributes"
sdkTypes "github.com/kairos-io/kairos-sdk/types"
"github.com/kairos-io/kairos-sdk/utils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/twpayne/go-vfs/v4/vfst"
)
func TestSuite(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Signatures Test Suite")
}
// This tests require prepared files to work unless we prepare them here in the test which is a bit costly
// 2 efi files, one signed and one unsigned
// fbx64.efi -> unsigned
// fbx64.signed.efi -> signed
// 2 db files extracted from a real db, one with the proper certificate that signed the efi file one without it
// db-wrong -> extracted db, contains signatures but they don't have the signature that signed the efi file
// db -> extracted db, contains signatures, including the one that signed the efi file
// 2 dbx files extracted from a real db, one that has nothing on it and one that has the efi file blacklisted
// TODO: have just 1 efi file and generate all of this on the fly:
// sign it when needed
// create the db/dbx efivars on the fly with the proper signatures
// Use efi.EfivarFs for this
var _ = Describe("Uki utils", Label("uki", "utils"), func() {
var fs sdkTypes.KairosFS
var logger sdkTypes.KairosLogger
var memLog *bytes.Buffer
var cleanup func()
BeforeEach(func() {
var err error
fs, cleanup, err = vfst.NewTestFS(map[string]interface{}{})
Expect(err).Should(BeNil())
// create fs with proper setup
err = utils.MkdirAll(fs, "/sys/firmware/efi/efivars", os.ModeDir|os.ModePerm)
Expect(err).ToNot(HaveOccurred())
file, err := os.ReadFile("tests/fbx64.efi")
Expect(err).ToNot(HaveOccurred())
err = fs.WriteFile("/efitest.efi", file, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
file, err = os.ReadFile("tests/fbx64.signed.efi")
Expect(err).ToNot(HaveOccurred())
err = fs.WriteFile("/efitest.signed.efi", file, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
memLog = &bytes.Buffer{}
logger = sdkTypes.NewBufferLogger(memLog)
// Override the Efivars location to point to our fake ones
// so the go-uefi lib looks in there
fakeEfivars, err := fs.RawPath("/sys/firmware/efi/efivars")
Expect(err).ToNot(HaveOccurred())
attributes.Efivars = fakeEfivars
})
AfterEach(func() {
cleanup()
})
It("Fails if it cant find the file to check", func() {
err := checkArtifactSignatureIsValid(fs, "/notexists.efi", logger)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("does not exist"))
})
It("Fails if the file is empty", func() {
// File needs to not be empty for the parser to try to parse it
err := fs.WriteFile("/nonefi.file", []byte(""), os.ModePerm)
Expect(err).ToNot(HaveOccurred())
err = checkArtifactSignatureIsValid(fs, "/nonefi.file", logger)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("has zero size"))
})
It("Fails if the file is not a valid efi file", func() {
// File needs to not be empty for the parser to try to parse it
err := fs.WriteFile("/nonefi.file", []byte("asdkljhfjklahsdfjk,hbasdfjkhas"), os.ModePerm)
Expect(err).ToNot(HaveOccurred())
err = checkArtifactSignatureIsValid(fs, "/nonefi.file", logger)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("not a PE file"))
})
It("Fails if the file to check has no signatures", func() {
dbFile := fmt.Sprintf("db-%s", attributes.EFI_IMAGE_SECURITY_DATABASE_GUID.Format())
file, err := os.ReadFile("tests/db")
Expect(err).ToNot(HaveOccurred())
err = fs.WriteFile(filepath.Join("/sys/firmware/efi/efivars", dbFile), file, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
err = checkArtifactSignatureIsValid(fs, "/efitest.efi", logger)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("no signatures in the file"))
})
It("fails when signature doesn't match the db", func() {
dbFile := fmt.Sprintf("db-%s", attributes.EFI_IMAGE_SECURITY_DATABASE_GUID.Format())
file, err := os.ReadFile("tests/db-wrong")
Expect(err).ToNot(HaveOccurred())
err = fs.WriteFile(filepath.Join("/sys/firmware/efi/efivars", dbFile), file, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
err = checkArtifactSignatureIsValid(fs, "/efitest.signed.efi", logger)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("could not find a signature in EFIVars DB that matches the artifact"))
})
It("matches the DB", func() {
dbFile := fmt.Sprintf("db-%s", attributes.EFI_IMAGE_SECURITY_DATABASE_GUID.Format())
file, err := os.ReadFile("tests/db")
Expect(err).ToNot(HaveOccurred())
err = fs.WriteFile(filepath.Join("/sys/firmware/efi/efivars", dbFile), file, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
err = checkArtifactSignatureIsValid(fs, "/efitest.signed.efi", logger)
Expect(err).ToNot(HaveOccurred())
})
It("doesn't fail when it matches the DB and not DBX", func() {
dbFile := fmt.Sprintf("db-%s", attributes.EFI_IMAGE_SECURITY_DATABASE_GUID.Format())
dbxFile := fmt.Sprintf("dbx-%s", attributes.EFI_IMAGE_SECURITY_DATABASE_GUID.Format())
file, err := os.ReadFile("tests/db")
Expect(err).ToNot(HaveOccurred())
err = fs.WriteFile(filepath.Join("/sys/firmware/efi/efivars", dbFile), file, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
file, err = os.ReadFile("tests/dbx-wrong")
Expect(err).ToNot(HaveOccurred())
err = fs.WriteFile(filepath.Join("/sys/firmware/efi/efivars", dbxFile), file, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
err = checkArtifactSignatureIsValid(fs, "/efitest.signed.efi", logger)
Expect(err).ToNot(HaveOccurred())
})
It("Fails if signature is in DBX, even if its also on DB", func() {
dbFile := fmt.Sprintf("db-%s", attributes.EFI_IMAGE_SECURITY_DATABASE_GUID.Format())
dbxFile := fmt.Sprintf("dbx-%s", attributes.EFI_IMAGE_SECURITY_DATABASE_GUID.Format())
file, err := os.ReadFile("tests/db")
Expect(err).ToNot(HaveOccurred())
err = fs.WriteFile(filepath.Join("/sys/firmware/efi/efivars", dbFile), file, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
file, err = os.ReadFile("tests/dbx")
Expect(err).ToNot(HaveOccurred())
err = fs.WriteFile(filepath.Join("/sys/firmware/efi/efivars", dbxFile), file, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
err = checkArtifactSignatureIsValid(fs, "/efitest.signed.efi", logger)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("hash appears on DBX"))
})
})