From a803d3b2b8cc913a69a6fa0298b01cbd3a36730c Mon Sep 17 00:00:00 2001 From: Fabian Wienand Date: Thu, 14 Sep 2023 12:57:55 +0200 Subject: [PATCH] feat: add option to remove specific certs from db instead of an entire reset Signed-off-by: Fabian Wienand --- cmd/sbctl/reset.go | 88 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 15 deletions(-) diff --git a/cmd/sbctl/reset.go b/cmd/sbctl/reset.go index 293bd9b..6cea800 100644 --- a/cmd/sbctl/reset.go +++ b/cmd/sbctl/reset.go @@ -4,18 +4,22 @@ import ( "errors" "fmt" "path/filepath" + "strings" "syscall" "github.com/foxboron/go-uefi/efi" + "github.com/foxboron/go-uefi/efi/signature" "github.com/foxboron/go-uefi/efi/util" "github.com/foxboron/sbctl" + "github.com/foxboron/sbctl/fs" "github.com/foxboron/sbctl/logging" "github.com/foxboron/sbctl/stringset" "github.com/spf13/cobra" ) type resetCmdOptions struct { - Partial stringset.StringSet + Partial stringset.StringSet + CertFiles string } var ( @@ -38,21 +42,27 @@ func resetKeys() error { return nil } + var paths []string + + if resetCmdOpts.CertFile != "" { + paths = strings.Split(resetCmdOpts.CertFile, ";") + } + switch partial := resetCmdOpts.Partial.Value; partial { case "db": - if err := resetDB(); err != nil { + if err := resetDB(paths...); err != nil { return err } case "dbx": - if err := resetDBX(); err != nil { + if err := resetDBX(paths...); err != nil { return err } case "KEK": - if err := resetKEK(); err != nil { + if err := resetKEK(paths...); err != nil { return err } case "PK": - if err := resetPK(); err != nil { + if err := resetPK(paths...); err != nil { return err } default: @@ -62,11 +72,11 @@ func resetKeys() error { return nil } -func resetDB() error { +func resetDB(certPaths ...string) error { KEKKey := filepath.Join(sbctl.KeysPath, "KEK", "KEK.key") KEKPem := filepath.Join(sbctl.KeysPath, "KEK", "KEK.pem") - if err := resetDatabase(KEKKey, KEKPem, "db"); err != nil { + if err := resetDatabase(KEKKey, KEKPem, "db", certPaths...); err != nil { return err } @@ -75,11 +85,11 @@ func resetDB() error { return nil } -func resetDBX() error { +func resetDBX(certPaths ...string) error { KEKKey := filepath.Join(sbctl.KeysPath, "KEK", "KEK.key") KEKPem := filepath.Join(sbctl.KeysPath, "KEK", "KEK.pem") - if err := resetDatabase(KEKKey, KEKPem, "dbx"); err != nil { + if err := resetDatabase(KEKKey, KEKPem, "dbx", certPaths...); err != nil { return err } @@ -88,11 +98,11 @@ func resetDBX() error { return nil } -func resetKEK() error { +func resetKEK(certPaths ...string) error { PKKey := filepath.Join(sbctl.KeysPath, "PK", "PK.key") PKPem := filepath.Join(sbctl.KeysPath, "PK", "PK.pem") - if err := resetDatabase(PKKey, PKPem, "KEK"); err != nil { + if err := resetDatabase(PKKey, PKPem, "KEK", certPaths...); err != nil { return err } @@ -101,11 +111,11 @@ func resetKEK() error { return nil } -func resetPK() error { +func resetPK(certPaths ...string) error { PKKey := filepath.Join(sbctl.KeysPath, "PK", "PK.key") PKPem := filepath.Join(sbctl.KeysPath, "PK", "PK.pem") - if err := resetDatabase(PKKey, PKPem, "PK"); err != nil { + if err := resetDatabase(PKKey, PKPem, "PK", certPaths...); err != nil { return err } @@ -114,7 +124,9 @@ func resetPK() error { return nil } -func resetDatabase(signerKey, signerPem string, efivar string) error { +func resetDatabase(signerKey, signerPem string, efivar string, certPaths ...string) error { + var buf []byte + key, err := util.ReadKeyFromFile(signerKey) if err != nil { return err @@ -125,7 +137,52 @@ func resetDatabase(signerKey, signerPem string, efivar string) error { return err } - signedBuf, err := efi.SignEFIVariable(key, crt, efivar, []byte{}) + if len(certPaths) != 0 { + var ( + db *signature.SignatureDatabase + err error + ) + + switch efivar { + case "db": + db, err = efi.Getdb() + case "dbx": + db, err = efi.Getdbx() + case "KEK": + db, err = efi.GetKEK() + case "PK": + db, err = efi.GetPK() + } + + if err != nil { + return err + } + + uuid, err := sbctl.GetGUID() + if err != nil { + return err + } + + guid := util.StringToGUID(uuid.String()) + + for _, certPath := range certPaths { + cert, err := fs.ReadFile(certPath) + if err != nil { + return fmt.Errorf("can't read new certificate from path %s: %v", certPath, err) + } + + if err := db.Remove(signature.CERT_X509_GUID, *guid, cert); err != nil { + return err + } + + } + + buf = db.Bytes() + } else { + buf = []byte{} + } + + signedBuf, err := efi.SignEFIVariable(key, crt, efivar, buf) if err != nil { return err } @@ -150,6 +207,7 @@ func RunReset(cmd *cobra.Command, args []string) error { func resetKeysCmdFlags(cmd *cobra.Command) { f := cmd.Flags() f.VarPF(&resetCmdOpts.Partial, "partial", "p", "reset a partial set of keys") + f.StringVarP(&resetCmdOpts.CertFiles, "cert-files", "c", "", "optional paths to certificate file to remove from db (seperate individual paths by ';')") } func init() {