sbctl/enroll-keys: Implement support for enrolling keys with go-uefi

This enrolls the keys using go-uefi. Essentially it reworks the
sbkeysync into a set of enroll commands taken from the go-uefi test
suite.

Preferably this should be more flexible e.g for key rotation.

Signed-off-by: Morten Linderud <morten@linderud.pw>
This commit is contained in:
Morten Linderud 2021-06-01 01:00:23 +02:00
parent 2d65668632
commit 9587644626
No known key found for this signature in database
GPG Key ID: E742683BA08CB2FF
2 changed files with 34 additions and 26 deletions

View File

@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"github.com/foxboron/go-uefi/efi/util"
"github.com/foxboron/sbctl"
"github.com/foxboron/sbctl/logging"
"github.com/spf13/cobra"
@ -35,13 +36,17 @@ var enrollKeysCmd = &cobra.Command{
if err := CheckImmutable(); err != nil {
return err
}
logging.Print("Syncing keys to EFI variables...")
synced := sbctl.SBKeySync(sbctl.KeysPath)
if !synced {
return errors.New("couldn't sync keys")
uuid, err := sbctl.GetGUID()
if err != nil {
return err
}
logging.Println("")
logging.Ok("Synced keys!")
guid := util.StringToGUID(uuid.String())
logging.Print("Enrolling keys to EFI variables...")
if err := sbctl.KeySync(*guid, sbctl.KeysPath); err != nil {
logging.NotOk("")
return fmt.Errorf("couldn't sync keys: %w", err)
}
logging.Ok("\nEnrolled keys to the EFI variables!")
return nil
},
}

43
keys.go
View File

@ -114,28 +114,31 @@ func SignEFIVariable(key, cert, varname, vardatafile, output string) ([]byte, er
return out, nil
}
func SBKeySync(dir string) bool {
cmd := exec.Command("sbkeysync", "--pk", "--verbose", "--keystore", dir)
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
if err := cmd.Run(); err != nil {
if exitError, ok := err.(*exec.ExitError); ok {
return exitError.ExitCode() == 0
}
func Enroll(uuid util.EFIGUID, cert, signerKey, signerPem []byte, efivar string) error {
c := signature.NewSignatureList(signature.CERT_X509_GUID)
c.AppendBytes(uuid, cert)
buf := new(bytes.Buffer)
signature.WriteSignatureList(buf, *c)
signedBuf := efi.SignEFIVariable(util.ReadKey(signerKey), util.ReadCert(signerPem), efivar, buf.Bytes())
return efi.WriteEFIVariable(efivar, signedBuf)
}
func KeySync(guid util.EFIGUID, keydir string) error {
PKKey, _ := os.ReadFile(filepath.Join(keydir, "PK", "PK.key"))
PKPem, _ := os.ReadFile(filepath.Join(keydir, "PK", "PK.pem"))
KEKKey, _ := os.ReadFile(filepath.Join(keydir, "KEK", "KEK.key"))
KEKPem, _ := os.ReadFile(filepath.Join(keydir, "KEK", "KEK.pem"))
dbPem, _ := os.ReadFile(filepath.Join(keydir, "db", "db.pem"))
if err := Enroll(guid, dbPem, KEKKey, KEKPem, "db"); err != nil {
return err
}
stdout := out.String()
for _, line := range strings.Split(stdout, "\n") {
if strings.Contains(line, "Operation not permitted") {
fmt.Println(stdout)
return false
}
if strings.Contains(line, "Permission denied") {
fmt.Println(stdout)
return false
}
if err := Enroll(guid, KEKPem, PKKey, PKPem, "KEK"); err != nil {
return err
}
return true
if err := Enroll(guid, PKPem, PKKey, PKPem, "PK"); err != nil {
return err
}
return nil
}
func VerifyFile(cert, file string) (bool, error) {