mirror of
https://github.com/kairos-io/kairos-sdk.git
synced 2025-05-09 16:46:32 +00:00
156 lines
6.4 KiB
Go
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"))
|
|
})
|
|
|
|
})
|