-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add method to validate signature of efi file (#337)
Co-authored-by: Dimitris Karakasilis <[email protected]>
- Loading branch information
1 parent
d4a9180
commit cfa2c61
Showing
12 changed files
with
370 additions
and
90 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
package uki | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"github.com/foxboron/go-uefi/efi/attributes" | ||
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1" | ||
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" | ||
sdkTypes "github.com/kairos-io/kairos-sdk/types" | ||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
"github.com/twpayne/go-vfs/v4/vfst" | ||
"os" | ||
"path/filepath" | ||
) | ||
|
||
// 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 v1.FS | ||
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 = fsutils.MkdirAll(fs, "/sys/firmware/efi/efivars", os.ModeDir|os.ModePerm) | ||
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")) | ||
}) | ||
|
||
}) |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Oops, something went wrong.