Skip to content

Commit

Permalink
Merge branch 'morten/setup'
Browse files Browse the repository at this point in the history
* morten/setup:
  ensure we always set output path to the file path
  sbctl: add check and unset immutable
  remove print
  sbctl.8: add config file and mention the new paths
  sbctl.8: mention the new --setup switch
  sbctl.8: fix some typesetting issues
  Implement sbctl setup
  enroll-key: separate runE from the invocation
  create-keys: separate RunE from the function invocation
  sbctl: read SetupMode from state.Efivarfs
  backend: ensure keyhierarchy reads from afero.Fs
  • Loading branch information
Foxboron committed Jul 28, 2024
2 parents 2403f4f + c666f43 commit 1454913
Show file tree
Hide file tree
Showing 22 changed files with 303 additions and 96 deletions.
20 changes: 10 additions & 10 deletions backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,36 +202,36 @@ func CreateKeys(c *config.Config) (*KeyHierarchy, error) {
return &hier, nil
}

func readKey(keydir string, kc *config.KeyConfig, hier hierarchy.Hierarchy) (KeyBackend, error) {
func readKey(vfs afero.Fs, keydir string, kc *config.KeyConfig, hier hierarchy.Hierarchy) (KeyBackend, error) {
switch kc.Type {
case "file", "":
return ReadFileKey(keydir, hier)
return ReadFileKey(vfs, keydir, hier)
}
return nil, nil
}

func GetKeyBackend(c *config.Config, k hierarchy.Hierarchy) (KeyBackend, error) {
func GetKeyBackend(vfs afero.Fs, c *config.Config, k hierarchy.Hierarchy) (KeyBackend, error) {
switch k {
case hierarchy.PK:
return readKey(c.Keydir, c.Keys.PK, k)
return readKey(vfs, c.Keydir, c.Keys.PK, k)
case hierarchy.KEK:
return readKey(c.Keydir, c.Keys.KEK, k)
return readKey(vfs, c.Keydir, c.Keys.KEK, k)
case hierarchy.Db:
return readKey(c.Keydir, c.Keys.Db, k)
return readKey(vfs, c.Keydir, c.Keys.Db, k)
}
return nil, nil
}

func GetKeyHierarchy(c *config.Config) (*KeyHierarchy, error) {
db, err := GetKeyBackend(c, hierarchy.Db)
func GetKeyHierarchy(vfs afero.Fs, c *config.Config) (*KeyHierarchy, error) {
db, err := GetKeyBackend(vfs, c, hierarchy.Db)
if err != nil {
return nil, err
}
kek, err := GetKeyBackend(c, hierarchy.KEK)
kek, err := GetKeyBackend(vfs, c, hierarchy.KEK)
if err != nil {
return nil, err
}
pk, err := GetKeyBackend(c, hierarchy.PK)
pk, err := GetKeyBackend(vfs, c, hierarchy.PK)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion backend/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestCreateKeys(t *testing.T) {
t.Fatalf("%v", err)
}

key, err := GetKeyBackend(c, hierarchy.PK)
key, err := GetKeyBackend(afero.NewOsFs(), c, hierarchy.PK)
if err != nil {
log.Fatal(err)
}
Expand Down
10 changes: 6 additions & 4 deletions backend/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import (
"encoding/pem"
"fmt"
"math/big"
"os"
"path/filepath"
"time"

"github.com/foxboron/sbctl/fs"

"github.com/foxboron/sbctl/hierarchy"
"github.com/spf13/afero"
)

var RSAKeySize = 4096
Expand Down Expand Up @@ -61,19 +63,19 @@ func NewFileKey(hier hierarchy.Hierarchy, desc string) (*FileKey, error) {
}, nil
}

func ReadFileKey(dir string, hier hierarchy.Hierarchy) (*FileKey, error) {
func ReadFileKey(vfs afero.Fs, dir string, hier hierarchy.Hierarchy) (*FileKey, error) {
path := filepath.Join(dir, hier.String())
keyname := filepath.Join(path, fmt.Sprintf("%s.key", hier.String()))
certname := filepath.Join(path, fmt.Sprintf("%s.pem", hier.String()))

// Read privatekey
keyb, err := os.ReadFile(keyname)
keyb, err := fs.ReadFile(vfs, keyname)
if err != nil {
return nil, err
}

// Read certificate
pemb, err := os.ReadFile(certname)
pemb, err := fs.ReadFile(vfs, certname)
if err != nil {
return nil, err
}
Expand Down
74 changes: 38 additions & 36 deletions cmd/sbctl/create-keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,49 +23,51 @@ var createKeysCmd = &cobra.Command{
Short: "Create a set of secure boot signing keys",
RunE: func(cmd *cobra.Command, args []string) error {
state := cmd.Context().Value(stateDataKey{}).(*config.State)
return RunCreateKeys(state)
},
}

// Overrides keydir or GUID location
if exportPath != "" {
state.Config.Keydir = exportPath
}
func RunCreateKeys(state *config.State) error {
// Overrides keydir or GUID location
if exportPath != "" {
state.Config.Keydir = exportPath
}

if databasePath != "" {
state.Config.GUID = databasePath
}
if databasePath != "" {
state.Config.GUID = databasePath
}

if err := sbctl.CreateDirectory(state.Fs, state.Config.Keydir); err != nil {
return err
}
if err := sbctl.CreateDirectory(state.Fs, path.Dir(state.Config.GUID)); err != nil {
return err
}
if err := sbctl.CreateDirectory(state.Fs, state.Config.Keydir); err != nil {
return err
}
if err := sbctl.CreateDirectory(state.Fs, path.Dir(state.Config.GUID)); err != nil {
return err
}

uuid, err := sbctl.CreateGUID(state.Fs, state.Config.GUID)
if err != nil {
return err
}
logging.Print("Created Owner UUID %s\n", uuid)
if !sbctl.CheckIfKeysInitialized(state.Fs, state.Config.Keydir) {
logging.Print("Creating secure boot keys...")

uuid, err := sbctl.CreateGUID(state.Fs, state.Config.GUID)
hier, err := backend.CreateKeys(state.Config)
if err != nil {
return err
logging.NotOk("")
return fmt.Errorf("couldn't initialize secure boot: %w", err)
}
logging.Print("Created Owner UUID %s\n", uuid)
fmt.Println(state.Config.Keydir)
if !sbctl.CheckIfKeysInitialized(state.Fs, state.Config.Keydir) {
logging.Print("Creating secure boot keys...")

hier, err := backend.CreateKeys(state.Config)
if err != nil {
logging.NotOk("")
return fmt.Errorf("couldn't initialize secure boot: %w", err)
}
err = hier.SaveKeys(state.Fs, state.Config.Keydir)
if err != nil {
logging.NotOk("")
return fmt.Errorf("couldn't initialize secure boot: %w", err)
}
logging.Ok("")
logging.Println("Secure boot keys created!")
} else {
logging.Ok("Secure boot keys have already been created!")
err = hier.SaveKeys(state.Fs, state.Config.Keydir)
if err != nil {
logging.NotOk("")
return fmt.Errorf("couldn't initialize secure boot: %w", err)
}
return nil
},
logging.Ok("")
logging.Println("Secure boot keys created!")
} else {
logging.Ok("Secure boot keys have already been created!")
}
return nil
}

func createKeysCmdFlags(cmd *cobra.Command) {
Expand Down
18 changes: 11 additions & 7 deletions cmd/sbctl/enroll-keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"strings"

"github.com/foxboron/go-uefi/efi"
"github.com/foxboron/go-uefi/efi/signature"
"github.com/foxboron/go-uefi/efivar"
"github.com/foxboron/sbctl"
Expand Down Expand Up @@ -59,7 +58,10 @@ var (
enrollKeysCmd = &cobra.Command{
Use: "enroll-keys",
Short: "Enroll the current keys to EFI",
RunE: RunEnrollKeys,
RunE: func(cmd *cobra.Command, args []string) error {
state := cmd.Context().Value(stateDataKey{}).(*config.State)
return RunEnrollKeys(state)
},
}
ErrSetupModeDisabled = errors.New("setup mode is disabled")
)
Expand All @@ -75,7 +77,7 @@ func SignSiglist(k *backend.KeyHierarchy, e efivar.Efivar, sigdb efivar.Marshall

// Sync keys from a key directory into efivarfs
func KeySync(state *config.State, oems []string) error {
kh, err := backend.GetKeyHierarchy(state.Config)
kh, err := backend.GetKeyHierarchy(state.Fs, state.Config)
if err != nil {
return err
}
Expand Down Expand Up @@ -243,11 +245,13 @@ func KeySync(state *config.State, oems []string) error {
return nil
}

func RunEnrollKeys(cmd *cobra.Command, args []string) error {
state := cmd.Context().Value(stateDataKey{}).(*config.State)

func RunEnrollKeys(state *config.State) error {
// SetupMode is not necessarily required on a partial enrollment
if !efi.GetSetupMode() && enrollKeysCmdOptions.Partial.Value == "" && enrollKeysCmdOptions.Export.Value == "" {
ok, err := state.Efivarfs.GetSetupMode()
if err != nil {
return err
}
if !ok && enrollKeysCmdOptions.Partial.Value == "" && enrollKeysCmdOptions.Export.Value == "" {
return ErrSetupModeDisabled
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/sbctl/generate-bundles.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ var generateBundlesCmd = &cobra.Command{
logging.Print("Wrote EFI bundle %s\n", bundle.Output)
if sign {
file := bundle.Output
kh, err := backend.GetKeyHierarchy(state.Config)
kh, err := backend.GetKeyHierarchy(state.Fs, state.Config)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/sbctl/list-bundles.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ var listBundlesCmd = &cobra.Command{
var isSigned bool
err := sbctl.BundleIter(state,
func(s *sbctl.Bundle) error {
kh, err := backend.GetKeyHierarchy(state.Config)
kh, err := backend.GetKeyHierarchy(state.Fs, state.Config)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/sbctl/list-files.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func RunList(cmd *cobra.Command, args []string) error {
var isSigned bool
err := sbctl.SigningEntryIter(state,
func(s *sbctl.SigningEntry) error {
kh, err := backend.GetKeyHierarchy(state.Config)
kh, err := backend.GetKeyHierarchy(state.Fs, state.Config)
if err != nil {
return err
}
Expand Down
2 changes: 2 additions & 0 deletions cmd/sbctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ func main() {
Fs: fs,
Config: conf,
Efivarfs: efivarfs.NewFS().
CheckImmutable().
UnsetImmutable().
Open(),
}
ctx := context.WithValue(context.Background(), stateDataKey{}, state)
Expand Down
2 changes: 1 addition & 1 deletion cmd/sbctl/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func resetDatabase(state *config.State, ev efivar.Efivar, certPaths ...string) e
}
}

kh, err := backend.GetKeyHierarchy(state.Config)
kh, err := backend.GetKeyHierarchy(state.Fs, state.Config)
if err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/sbctl/rotate-keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func RunRotateKeys(cmd *cobra.Command, args []string) error {
}

func rotateAllKeys(state *config.State, backupDir, newKeysDir string) error {
oldKeys, err := backend.GetKeyHierarchy(state.Config)
oldKeys, err := backend.GetKeyHierarchy(state.Fs, state.Config)
if err != nil {
return fmt.Errorf("can't read old keys from dir: %v", err)
}
Expand Down Expand Up @@ -172,7 +172,7 @@ func rotateKey(state *config.State, hiera string, keyPath, certPath string) erro
return fmt.Errorf("a new certificate needs to be provided for a partial reset of %s", hiera)
}

oldKH, err := backend.GetKeyHierarchy(state.Config)
oldKH, err := backend.GetKeyHierarchy(state.Fs, state.Config)
if err != nil {
return fmt.Errorf("can't read old keys from dir: %v", err)
}
Expand All @@ -188,7 +188,7 @@ func rotateKey(state *config.State, hiera string, keyPath, certPath string) erro
}

// We will mutate this to the new state
newKH, err := backend.GetKeyHierarchy(state.Config)
newKH, err := backend.GetKeyHierarchy(state.Fs, state.Config)
if err != nil {
return fmt.Errorf("can't read old keys from dir: %v", err)
}
Expand Down
51 changes: 51 additions & 0 deletions cmd/sbctl/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type SetupCmdOptions struct {
PrintConfig bool
PrintState bool
Migrate bool
Setup bool
}

var (
Expand Down Expand Up @@ -83,6 +84,49 @@ func PrintConfig(state *config.State) error {
return nil
}

func SetupInstallation(state *config.State) error {
if ok, _ := state.Efivarfs.GetSetupMode(); !ok {
return ErrSetupModeDisabled
}
if state.IsInstalled() {
return fmt.Errorf("sbctl is already installed")
}

if err := RunCreateKeys(state); err != nil {
return err
}

if err := RunEnrollKeys(state); err != nil {
return err
}

if len(state.Config.Files) == 0 {
return nil
}

files, err := sbctl.ReadFileDatabase(state.Fs, state.Config.FilesDb)
if err != nil {
return err
}

for _, f := range state.Config.Files {
if f.Output == "" {
f.Output = f.Path
}
files[f.Path] = &sbctl.SigningEntry{File: f.Path, OutputFile: f.Output}
}

if err := sbctl.WriteFileDatabase(state.Fs, state.Config.FilesDb, files); err != nil {
return err
}

if err := SignAll(state); err != nil {
return err
}

return nil
}

func MigrateSetup(state *config.State) error {
newConf := config.DefaultConfig()
p := path.Dir(newConf.Keydir)
Expand Down Expand Up @@ -122,6 +166,12 @@ func MigrateSetup(state *config.State) error {
func RunSetup(cmd *cobra.Command, args []string) error {
state := cmd.Context().Value(stateDataKey{}).(*config.State)

if setupCmdOptions.Setup {
if err := SetupInstallation(state); err != nil {
return err
}
}

if setupCmdOptions.Migrate {
if err := MigrateSetup(state); err != nil {
return err
Expand All @@ -140,6 +190,7 @@ func setupCmdFlags(cmd *cobra.Command) {
f.BoolVarP(&setupCmdOptions.PrintConfig, "print-config", "", false, "print config file")
f.BoolVarP(&setupCmdOptions.PrintState, "print-state", "", false, "print the state of sbctl")
f.BoolVarP(&setupCmdOptions.Migrate, "migrate", "", false, "migrate the sbctl installation")
f.BoolVarP(&setupCmdOptions.Setup, "setup", "", false, "setup the sbctl installation")
}

func init() {
Expand Down
Loading

0 comments on commit 1454913

Please sign in to comment.