mirror of https://github.com/ericonr/sbctl.git
New structure
Signed-off-by: Morten Linderud <morten@linderud.pw>
This commit is contained in:
parent
adadb52e73
commit
3505f1b571
29
bundles.go
29
bundles.go
|
@ -8,7 +8,6 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/foxboron/sbctl/logging"
|
||||
)
|
||||
|
@ -126,31 +125,3 @@ func GenerateBundle(bundle *Bundle) (bool, error) {
|
|||
logging.Print("Wrote EFI bundle %s\n", bundle.Output)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func FormatBundle(name string, bundle *Bundle) {
|
||||
logging.Println(name)
|
||||
logging.Print("\tSigned:\t\t")
|
||||
if ok, _ := VerifyFile(DBCert, name); ok {
|
||||
logging.Ok("Signed")
|
||||
} else {
|
||||
logging.NotOk("Not Signed")
|
||||
}
|
||||
esp := GetESP()
|
||||
logging.Print("\tESP Location:\t%s\n", esp)
|
||||
logging.Print("\tOutput:\t\t└─%s\n", strings.TrimPrefix(bundle.Output, esp))
|
||||
logging.Print("\tEFI Stub Image:\t └─%s\n", bundle.EFIStub)
|
||||
if bundle.Splash != "" {
|
||||
logging.Print("\tSplash Image:\t ├─%s\n", bundle.Splash)
|
||||
}
|
||||
logging.Print("\tCmdline:\t ├─%s\n", bundle.Cmdline)
|
||||
logging.Print("\tOS Release:\t ├─%s\n", bundle.OSRelease)
|
||||
logging.Print("\tKernel Image:\t ├─%s\n", bundle.KernelImage)
|
||||
logging.Print("\tInitramfs Image: └─%s\n", bundle.Initramfs)
|
||||
if bundle.AMDMicrocode != "" {
|
||||
logging.Print("\tAMD Microcode: └─%s\n", bundle.AMDMicrocode)
|
||||
}
|
||||
if bundle.IntelMicrocode != "" {
|
||||
logging.Print("\tIntel Microcode: └─%s\n", bundle.IntelMicrocode)
|
||||
}
|
||||
logging.Println("")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/foxboron/sbctl"
|
||||
"github.com/foxboron/sbctl/logging"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
amducode string
|
||||
intelucode string
|
||||
splashImg string
|
||||
osRelease string
|
||||
efiStub string
|
||||
kernelImg string
|
||||
cmdline string
|
||||
initramfs string
|
||||
espPath string
|
||||
saveBundle bool
|
||||
)
|
||||
|
||||
var bundleCmd = &cobra.Command{
|
||||
Use: "bundle",
|
||||
Short: "Bundle the needed files for an EFI stub image",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
logging.Print("Requires a file to sign...\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
checkFiles := []string{amducode, intelucode, splashImg, osRelease, efiStub, kernelImg, cmdline, initramfs}
|
||||
for _, path := range checkFiles {
|
||||
if path == "" {
|
||||
continue
|
||||
}
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
logging.Print("%s does not exist!\n", path)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
bundle := sbctl.NewBundle()
|
||||
output, err := filepath.Abs(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Fail early if user wants to save bundle but doesn't have permissions
|
||||
var bundles sbctl.Bundles
|
||||
if saveBundle {
|
||||
// "err" needs to have been declared before this, otherwise it's necessary
|
||||
// to use ":=", which shadows the "bundles" variable
|
||||
bundles, err = sbctl.ReadBundleDatabase(sbctl.BundleDBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
bundle.Output = output
|
||||
bundle.IntelMicrocode = intelucode
|
||||
bundle.AMDMicrocode = amducode
|
||||
bundle.KernelImage = kernelImg
|
||||
bundle.Initramfs = initramfs
|
||||
bundle.Cmdline = cmdline
|
||||
bundle.Splash = splashImg
|
||||
bundle.OSRelease = osRelease
|
||||
bundle.EFIStub = efiStub
|
||||
bundle.ESP = espPath
|
||||
if err = sbctl.CreateBundle(*bundle); err != nil {
|
||||
return err
|
||||
}
|
||||
if saveBundle {
|
||||
bundles[bundle.Output] = bundle
|
||||
sbctl.WriteBundleDatabase(sbctl.BundleDBPath, bundles)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func bundleCmdFlags(cmd *cobra.Command) {
|
||||
esp := sbctl.GetESP()
|
||||
f := cmd.Flags()
|
||||
f.StringVarP(&amducode, "amducode", "a", "", "AMD microcode location")
|
||||
f.StringVarP(&intelucode, "intelucode", "i", "", "Intel microcode location")
|
||||
f.StringVarP(&splashImg, "splash-img", "l", "", "Boot splash image location")
|
||||
f.StringVarP(&osRelease, "os-release", "o", "/usr/lib/os-release", "OS Release file location")
|
||||
f.StringVarP(&efiStub, "efi-stub", "e", "/usr/lib/systemd/boot/efi/linuxx64.efi.stub", "EFI Stub location")
|
||||
f.StringVarP(&kernelImg, "kernel-img", "k", "/boot/vmlinuz-linux", "Kernel image location")
|
||||
f.StringVarP(&cmdline, "cmdline", "c", "/etc/kernel/cmdline", "Cmdline location")
|
||||
f.StringVarP(&initramfs, "initramfs", "f", "/boot/initramfs-linux.img", "Initramfs location")
|
||||
f.StringVarP(&espPath, "esp", "p", esp, "ESP location")
|
||||
f.BoolVarP(&saveBundle, "save", "s", false, "save bundle to the database")
|
||||
}
|
||||
|
||||
func init() {
|
||||
bundleCmdFlags(bundleCmd)
|
||||
CliCommands = append(CliCommands, cliCommand{
|
||||
Cmd: bundleCmd,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var completionCmd = &cobra.Command{Use: "completion"}
|
||||
|
||||
func completionBashCmd() *cobra.Command {
|
||||
var completionCmd = &cobra.Command{
|
||||
Use: "bash",
|
||||
Hidden: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
rootCmd.GenBashCompletion(os.Stdout)
|
||||
},
|
||||
}
|
||||
return completionCmd
|
||||
}
|
||||
|
||||
func completionZshCmd() *cobra.Command {
|
||||
var completionCmd = &cobra.Command{
|
||||
Use: "zsh",
|
||||
Hidden: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
rootCmd.GenZshCompletion(os.Stdout)
|
||||
},
|
||||
}
|
||||
return completionCmd
|
||||
}
|
||||
|
||||
func completionFishCmd() *cobra.Command {
|
||||
var completionCmd = &cobra.Command{
|
||||
Use: "fish",
|
||||
Hidden: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
rootCmd.GenFishCompletion(os.Stdout, true)
|
||||
},
|
||||
}
|
||||
return completionCmd
|
||||
}
|
||||
|
||||
func init() {
|
||||
completionCmd.AddCommand(completionBashCmd())
|
||||
completionCmd.AddCommand(completionZshCmd())
|
||||
completionCmd.AddCommand(completionFishCmd())
|
||||
CliCommands = append(CliCommands, cliCommand{
|
||||
Cmd: completionCmd,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/foxboron/sbctl"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var createKeysCmd = &cobra.Command{
|
||||
Use: "create-keys",
|
||||
Short: "Create a set of secure boot signing keys",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return sbctl.CreateKeys()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
CliCommands = append(CliCommands, cliCommand{
|
||||
Cmd: createKeysCmd,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/foxboron/sbctl"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var enrollKeysCmd = &cobra.Command{
|
||||
Use: "enroll-keys",
|
||||
Short: "Enroll the current keys to EFI",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return sbctl.SyncKeys()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
CliCommands = append(CliCommands, cliCommand{
|
||||
Cmd: enrollKeysCmd,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/foxboron/sbctl"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
sign bool
|
||||
)
|
||||
|
||||
var generateBundlesCmd = &cobra.Command{
|
||||
Use: "generate-bundles",
|
||||
Short: "Generate all EFI stub bundles",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return sbctl.GenerateAllBundles(sign)
|
||||
},
|
||||
}
|
||||
|
||||
func generateBundlesCmdFlags(cmd *cobra.Command) {
|
||||
f := cmd.Flags()
|
||||
f.BoolVarP(&sign, "sign", "s", false, "Sign all the generated bundles")
|
||||
}
|
||||
|
||||
func init() {
|
||||
generateBundlesCmdFlags(generateBundlesCmd)
|
||||
CliCommands = append(CliCommands, cliCommand{
|
||||
Cmd: generateBundlesCmd,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/foxboron/sbctl"
|
||||
"github.com/foxboron/sbctl/logging"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type JsonBundle struct {
|
||||
sbctl.Bundle
|
||||
IsSigned bool `json:"is_signed"`
|
||||
}
|
||||
|
||||
var listBundlesCmd = &cobra.Command{
|
||||
Use: "list-bundles",
|
||||
Short: "List stored bundles",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
bundles := []JsonBundle{}
|
||||
var isSigned bool
|
||||
err := sbctl.BundleIter(
|
||||
func(s *sbctl.Bundle) error {
|
||||
ok, err := sbctl.VerifyFile(sbctl.DBCert, s.Output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logging.Println("Enrolled bundles:\n")
|
||||
logging.Println(s.Output)
|
||||
logging.Print("\tSigned:\t\t")
|
||||
if ok {
|
||||
isSigned = true
|
||||
logging.Ok("Signed")
|
||||
} else {
|
||||
isSigned = false
|
||||
logging.NotOk("Not Signed")
|
||||
}
|
||||
esp := sbctl.GetESP()
|
||||
logging.Print("\tESP Location:\t%s\n", esp)
|
||||
logging.Print("\tOutput:\t\t└─%s\n", strings.TrimPrefix(s.Output, esp))
|
||||
logging.Print("\tEFI Stub Image:\t └─%s\n", s.EFIStub)
|
||||
if s.Splash != "" {
|
||||
logging.Print("\tSplash Image:\t ├─%s\n", s.Splash)
|
||||
}
|
||||
logging.Print("\tCmdline:\t ├─%s\n", s.Cmdline)
|
||||
logging.Print("\tOS Release:\t ├─%s\n", s.OSRelease)
|
||||
logging.Print("\tKernel Image:\t ├─%s\n", s.KernelImage)
|
||||
logging.Print("\tInitramfs Image: └─%s\n", s.Initramfs)
|
||||
if s.AMDMicrocode != "" {
|
||||
logging.Print("\tAMD Microcode: └─%s\n", s.AMDMicrocode)
|
||||
}
|
||||
if s.IntelMicrocode != "" {
|
||||
logging.Print("\tIntel Microcode: └─%s\n", s.IntelMicrocode)
|
||||
}
|
||||
bundles = append(bundles, JsonBundle{*s, isSigned})
|
||||
logging.Println("")
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cmdOptions.JsonOutput {
|
||||
JsonOut(bundles)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
CliCommands = append(CliCommands, cliCommand{
|
||||
Cmd: listBundlesCmd,
|
||||
})
|
||||
}
|
|
@ -52,330 +52,7 @@ func JsonOut(v interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func createKeysCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "create-keys",
|
||||
Short: "Create a set of secure boot signing keys",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return sbctl.CreateKeys()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func enrollKeysCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "enroll-keys",
|
||||
Short: "Enroll the current keys to EFI",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return sbctl.SyncKeys()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func signCmd() *cobra.Command {
|
||||
var save bool
|
||||
var output string
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "sign",
|
||||
Short: "Sign a file with secure boot keys",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
logging.Print("Requires a file to sign\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Ensure we have absolute paths
|
||||
file, err := filepath.Abs(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if output == "" {
|
||||
output = file
|
||||
} else {
|
||||
output, err = filepath.Abs(output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := sbctl.Sign(file, output, save); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
f := cmd.Flags()
|
||||
f.BoolVarP(&save, "save", "s", false, "save file to the database")
|
||||
f.StringVarP(&output, "output", "o", "", "output filename. Default replaces the file")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func signAllCmd() *cobra.Command {
|
||||
var generate bool
|
||||
cmd := &cobra.Command{
|
||||
Use: "sign-all",
|
||||
Short: "Sign all enrolled files with secure boot keys",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if generate {
|
||||
if err := sbctl.GenerateAllBundles(true); err != nil {
|
||||
logging.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
files, err := sbctl.ReadFileDatabase(sbctl.DBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range files {
|
||||
|
||||
if err := sbctl.SignFile(sbctl.DBKey, sbctl.DBCert, entry.File, entry.OutputFile, entry.Checksum); err != nil {
|
||||
logging.Fatal(err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Update checksum after we signed it
|
||||
checksum := sbctl.ChecksumFile(entry.File)
|
||||
entry.Checksum = checksum
|
||||
files[entry.File] = entry
|
||||
sbctl.WriteFileDatabase(sbctl.DBPath, files)
|
||||
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
f := cmd.Flags()
|
||||
f.BoolVarP(&generate, "generate", "g", false, "run all generate-* sub-commands before signing")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func removeFileCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "remove-file",
|
||||
Short: "Remove file from database",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
logging.Println("Need to specify file")
|
||||
os.Exit(1)
|
||||
}
|
||||
files, err := sbctl.ReadFileDatabase(sbctl.DBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := files[args[0]]; !ok {
|
||||
logging.Print("File %s doesn't exist in database!\n", args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
delete(files, args[0])
|
||||
sbctl.WriteFileDatabase(sbctl.DBPath, files)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func verifyCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "verify",
|
||||
Short: "Find and check if files in the ESP are signed or not",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := sbctl.VerifyESP(); err != nil {
|
||||
// Really need to sort out the low level error handling
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func bundleCmd() *cobra.Command {
|
||||
var amducode string
|
||||
var intelucode string
|
||||
var splashImg string
|
||||
var osRelease string
|
||||
var efiStub string
|
||||
var kernelImg string
|
||||
var cmdline string
|
||||
var initramfs string
|
||||
var espPath string
|
||||
var save bool
|
||||
cmd := &cobra.Command{
|
||||
Use: "bundle",
|
||||
Short: "Bundle the needed files for an EFI stub image",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
logging.Print("Requires a file to sign...\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
checkFiles := []string{amducode, intelucode, splashImg, osRelease, efiStub, kernelImg, cmdline, initramfs}
|
||||
for _, path := range checkFiles {
|
||||
if path == "" {
|
||||
continue
|
||||
}
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
logging.Print("%s does not exist!\n", path)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
bundle := sbctl.NewBundle()
|
||||
output, err := filepath.Abs(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Fail early if user wants to save bundle but doesn't have permissions
|
||||
var bundles sbctl.Bundles
|
||||
if save {
|
||||
// "err" needs to have been declared before this, otherwise it's necessary
|
||||
// to use ":=", which shadows the "bundles" variable
|
||||
bundles, err = sbctl.ReadBundleDatabase(sbctl.BundleDBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
bundle.Output = output
|
||||
bundle.IntelMicrocode = intelucode
|
||||
bundle.AMDMicrocode = amducode
|
||||
bundle.KernelImage = kernelImg
|
||||
bundle.Initramfs = initramfs
|
||||
bundle.Cmdline = cmdline
|
||||
bundle.Splash = splashImg
|
||||
bundle.OSRelease = osRelease
|
||||
bundle.EFIStub = efiStub
|
||||
bundle.ESP = espPath
|
||||
if err = sbctl.CreateBundle(*bundle); err != nil {
|
||||
return err
|
||||
}
|
||||
if save {
|
||||
bundles[bundle.Output] = bundle
|
||||
sbctl.WriteBundleDatabase(sbctl.BundleDBPath, bundles)
|
||||
sbctl.FormatBundle(bundle.Output, bundle)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
esp := sbctl.GetESP()
|
||||
f := cmd.Flags()
|
||||
f.StringVarP(&amducode, "amducode", "a", "", "AMD microcode location")
|
||||
f.StringVarP(&intelucode, "intelucode", "i", "", "Intel microcode location")
|
||||
f.StringVarP(&splashImg, "splash-img", "l", "", "Boot splash image location")
|
||||
f.StringVarP(&osRelease, "os-release", "o", "/usr/lib/os-release", "OS Release file location")
|
||||
f.StringVarP(&efiStub, "efi-stub", "e", "/usr/lib/systemd/boot/efi/linuxx64.efi.stub", "EFI Stub location")
|
||||
f.StringVarP(&kernelImg, "kernel-img", "k", "/boot/vmlinuz-linux", "Kernel image location")
|
||||
f.StringVarP(&cmdline, "cmdline", "c", "/etc/kernel/cmdline", "Cmdline location")
|
||||
f.StringVarP(&initramfs, "initramfs", "f", "/boot/initramfs-linux.img", "Initramfs location")
|
||||
f.StringVarP(&espPath, "esp", "p", esp, "ESP location")
|
||||
f.BoolVarP(&save, "save", "s", false, "save bundle to the database")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func generateBundlesCmd() *cobra.Command {
|
||||
var sign bool
|
||||
cmd := &cobra.Command{
|
||||
Use: "generate-bundles",
|
||||
Short: "Generate all EFI stub bundles",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return sbctl.GenerateAllBundles(sign)
|
||||
},
|
||||
}
|
||||
f := cmd.Flags()
|
||||
f.BoolVarP(&sign, "sign", "s", false, "Sign all the generated bundles")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func listBundlesCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "list-bundles",
|
||||
Short: "List stored bundles",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
_, err := sbctl.ListBundles()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func removeBundleCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "remove-bundle",
|
||||
Short: "Remove bundle from database",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
logging.Print("Need to specify file\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
bundles, err := sbctl.ReadBundleDatabase(sbctl.BundleDBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, ok := bundles[args[0]]; !ok {
|
||||
logging.Print("Bundle %s doesn't exist in database!\n", args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
delete(bundles, args[0])
|
||||
sbctl.WriteBundleDatabase(sbctl.BundleDBPath, bundles)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func completionBashCmd() *cobra.Command {
|
||||
var completionCmd = &cobra.Command{
|
||||
Use: "bash",
|
||||
Hidden: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
rootCmd.GenBashCompletion(os.Stdout)
|
||||
},
|
||||
}
|
||||
return completionCmd
|
||||
}
|
||||
|
||||
func completionZshCmd() *cobra.Command {
|
||||
var completionCmd = &cobra.Command{
|
||||
Use: "zsh",
|
||||
Hidden: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
rootCmd.GenZshCompletion(os.Stdout)
|
||||
},
|
||||
}
|
||||
return completionCmd
|
||||
}
|
||||
|
||||
func completionFishCmd() *cobra.Command {
|
||||
var completionCmd = &cobra.Command{
|
||||
Use: "fish",
|
||||
Hidden: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
rootCmd.GenFishCompletion(os.Stdout, true)
|
||||
},
|
||||
}
|
||||
return completionCmd
|
||||
}
|
||||
|
||||
func main() {
|
||||
cmds := []*cobra.Command{
|
||||
createKeysCmd(),
|
||||
enrollKeysCmd(),
|
||||
signCmd(),
|
||||
signAllCmd(),
|
||||
verifyCmd(),
|
||||
bundleCmd(),
|
||||
generateBundlesCmd(),
|
||||
removeBundleCmd(),
|
||||
listBundlesCmd(),
|
||||
removeFileCmd(),
|
||||
}
|
||||
for _, c := range cmds {
|
||||
rootCmd.AddCommand(c)
|
||||
}
|
||||
|
||||
completionCmd := &cobra.Command{Use: "completion"}
|
||||
completionCmd.AddCommand(completionBashCmd())
|
||||
completionCmd.AddCommand(completionZshCmd())
|
||||
completionCmd.AddCommand(completionFishCmd())
|
||||
rootCmd.AddCommand(completionCmd)
|
||||
|
||||
for _, cmd := range CliCommands {
|
||||
baseFlags(cmd.Cmd)
|
||||
rootCmd.AddCommand(cmd.Cmd)
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/foxboron/sbctl"
|
||||
"github.com/foxboron/sbctl/logging"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var removeBundleCmd = &cobra.Command{
|
||||
Use: "remove-bundle",
|
||||
Short: "Remove bundle from database",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
logging.Print("Need to specify file\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
bundles, err := sbctl.ReadBundleDatabase(sbctl.BundleDBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, ok := bundles[args[0]]; !ok {
|
||||
logging.Print("Bundle %s doesn't exist in database!\n", args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
delete(bundles, args[0])
|
||||
sbctl.WriteBundleDatabase(sbctl.BundleDBPath, bundles)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
CliCommands = append(CliCommands, cliCommand{
|
||||
Cmd: removeBundleCmd,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/foxboron/sbctl"
|
||||
"github.com/foxboron/sbctl/logging"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var removeFileCmd = &cobra.Command{
|
||||
Use: "remove-file",
|
||||
Short: "Remove file from database",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
logging.Println("Need to specify file")
|
||||
os.Exit(1)
|
||||
}
|
||||
files, err := sbctl.ReadFileDatabase(sbctl.DBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := files[args[0]]; !ok {
|
||||
logging.Print("File %s doesn't exist in database!\n", args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
delete(files, args[0])
|
||||
sbctl.WriteFileDatabase(sbctl.DBPath, files)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
CliCommands = append(CliCommands, cliCommand{
|
||||
Cmd: removeFileCmd,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/foxboron/sbctl"
|
||||
"github.com/foxboron/sbctl/logging"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
generate bool
|
||||
)
|
||||
|
||||
var signAllCmd = &cobra.Command{
|
||||
Use: "sign-all",
|
||||
Short: "Sign all enrolled files with secure boot keys",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if generate {
|
||||
if err := sbctl.GenerateAllBundles(true); err != nil {
|
||||
logging.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
files, err := sbctl.ReadFileDatabase(sbctl.DBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range files {
|
||||
|
||||
if err := sbctl.SignFile(sbctl.DBKey, sbctl.DBCert, entry.File, entry.OutputFile, entry.Checksum); err != nil {
|
||||
logging.Fatal(err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Update checksum after we signed it
|
||||
checksum := sbctl.ChecksumFile(entry.File)
|
||||
entry.Checksum = checksum
|
||||
files[entry.File] = entry
|
||||
sbctl.WriteFileDatabase(sbctl.DBPath, files)
|
||||
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func signAllCmdFlags(cmd *cobra.Command) {
|
||||
f := cmd.Flags()
|
||||
f.BoolVarP(&generate, "generate", "g", false, "run all generate-* sub-commands before signing")
|
||||
}
|
||||
|
||||
func init() {
|
||||
signAllCmdFlags(signAllCmd)
|
||||
CliCommands = append(CliCommands, cliCommand{
|
||||
Cmd: signAllCmd,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/foxboron/sbctl"
|
||||
"github.com/foxboron/sbctl/logging"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
save bool
|
||||
output string
|
||||
)
|
||||
|
||||
var signCmd = &cobra.Command{
|
||||
Use: "sign",
|
||||
Short: "Sign a file with secure boot keys",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
logging.Print("Requires a file to sign\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Ensure we have absolute paths
|
||||
file, err := filepath.Abs(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if output == "" {
|
||||
output = file
|
||||
} else {
|
||||
output, err = filepath.Abs(output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := sbctl.Sign(file, output, save); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func signCmdFlags(cmd *cobra.Command) {
|
||||
f := cmd.Flags()
|
||||
f.BoolVarP(&save, "save", "s", false, "save file to the database")
|
||||
f.StringVarP(&output, "output", "o", "", "output filename. Default replaces the file")
|
||||
}
|
||||
|
||||
func init() {
|
||||
signCmdFlags(signCmd)
|
||||
CliCommands = append(CliCommands, cliCommand{
|
||||
Cmd: signCmd,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/foxboron/sbctl"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var verifyCmd = &cobra.Command{
|
||||
Use: "verify",
|
||||
Short: "Find and check if files in the ESP are signed or not",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := sbctl.VerifyESP(); err != nil {
|
||||
// Really need to sort out the low level error handling
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
CliCommands = append(CliCommands, cliCommand{
|
||||
Cmd: verifyCmd,
|
||||
})
|
||||
}
|
12
sbctl.go
12
sbctl.go
|
@ -341,15 +341,3 @@ func GenerateAllBundles(sign bool) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ListBundles() (Bundles, error) {
|
||||
bundles, err := ReadBundleDatabase(BundleDBPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't open database: %v", err)
|
||||
}
|
||||
logging.Println("Enrolled bundles:\n")
|
||||
for key, bundle := range bundles {
|
||||
FormatBundle(key, bundle)
|
||||
}
|
||||
return bundles, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue