diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 25cc145..5404c47 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,6 +20,9 @@ jobs: libdevmapper-dev libacl1-dev libarchive-tools pip squashfs-tools \ sbsigntool pip install virt-firmware + - name: lint + run: | + make gofmt - name: build run: | make diff --git a/.gitignore b/.gitignore index e69de29..5430407 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +.made-gofmt diff --git a/Makefile b/Makefile index 72b6cc3..4c1c82b 100644 --- a/Makefile +++ b/Makefile @@ -5,10 +5,20 @@ ifeq ($(MAIN_VERSION),$(filter $(MAIN_VERSION), "", no-git)) $(error "Bad value for MAIN_VERSION: '$(MAIN_VERSION)'") endif +GO_SRC_DIRS := pkg/ cmd/ +GO_SRC := $(shell find $(GO_SRC_DIRS) -name "*.go") + VERSION_LDFLAGS=-X github.com/project-machine/trust/pkg/trust.Version=$(MAIN_VERSION) -trust: cmd/trust/*.go pkg/trust/*.go pkg/printdirtree/*.go +trust: .made-gofmt $(GO_SRC) go build -buildvcs=false -ldflags "$(VERSION_LDFLAGS)" -o trust ./cmd/trust/ +.PHONY: gofmt +gofmt: .made-gofmt +.made-gofmt: $(GO_SRC) + o=$$(gofmt -l -w $(GO_SRC_DIRS) 2>&1) && [ -z "$$o" ] || \ + { echo "gofmt made changes: $$o" 1>&2; exit 1; } + @touch $@ + clean: rm -f trust diff --git a/cmd/trust/computepcr.go b/cmd/trust/computepcr.go index 490f17e..165ad33 100644 --- a/cmd/trust/computepcr.go +++ b/cmd/trust/computepcr.go @@ -4,8 +4,8 @@ import ( "errors" "fmt" - "github.com/urfave/cli" "github.com/project-machine/trust/pkg/trust" + "github.com/urfave/cli" ) var computePCR7Cmd = cli.Command{ diff --git a/cmd/trust/extendpcr.go b/cmd/trust/extendpcr.go index e36b8ab..468579c 100644 --- a/cmd/trust/extendpcr.go +++ b/cmd/trust/extendpcr.go @@ -1,8 +1,8 @@ package main import ( - "github.com/urfave/cli" "github.com/project-machine/trust/pkg/trust" + "github.com/urfave/cli" ) var extendPCR7Cmd = cli.Command{ diff --git a/cmd/trust/main.go b/cmd/trust/main.go index b2eba66..1f6af64 100644 --- a/cmd/trust/main.go +++ b/cmd/trust/main.go @@ -39,7 +39,6 @@ func main() { // verify verifyCmd, - } app.Flags = []cli.Flag{ cli.BoolFlag{ diff --git a/cmd/trust/policygen.go b/cmd/trust/policygen.go index 6fa15ea..f4e5c97 100644 --- a/cmd/trust/policygen.go +++ b/cmd/trust/policygen.go @@ -1,11 +1,11 @@ package main import ( - "os" "errors" + "os" - "github.com/urfave/cli" "github.com/project-machine/trust/pkg/trust" + "github.com/urfave/cli" ) var tpmPolicyGenCmd = cli.Command{ diff --git a/cmd/trust/project.go b/cmd/trust/project.go index 85d9411..7ac962e 100644 --- a/cmd/trust/project.go +++ b/cmd/trust/project.go @@ -93,7 +93,7 @@ func doListProjects(ctx *cli.Context) error { return nil } - dirs, err := os.ReadDir(keysetPath) + dirs, err := os.ReadDir(keysetPath) if err != nil { return fmt.Errorf("Failed reading keys directory %q: %w", trustDir, err) } diff --git a/cmd/trust/sign.go b/cmd/trust/sign.go index d145bc0..1d865df 100644 --- a/cmd/trust/sign.go +++ b/cmd/trust/sign.go @@ -9,25 +9,25 @@ import ( ) var signCmd = cli.Command{ - Name: "sign", + Name: "sign", Usage: "Create Digital Signature", Subcommands: []cli.Command{ cli.Command{ - Name: "efi", - Action: doSignEFI, - Usage: "sign an efi binary", + Name: "efi", + Action: doSignEFI, + Usage: "sign an efi binary", ArgsUsage: "", Flags: []cli.Flag{ cli.StringFlag{ - Name: "key", + Name: "key", Usage: "The private key to sign the efi binary.", }, cli.StringFlag{ - Name: "cert", + Name: "cert", Usage: "The X509 certificate for creating signature.", }, cli.StringFlag{ - Name: "output", + Name: "output", Usage: "PathName for the signed efi binary.", }, }, diff --git a/cmd/trust/sudi.go b/cmd/trust/sudi.go index 49637ab..0eef5b5 100644 --- a/cmd/trust/sudi.go +++ b/cmd/trust/sudi.go @@ -35,8 +35,9 @@ var sudiCmd = cli.Command{ } // ~/.local/share/machine/trust/keys/ -// keyset1/manifest/project-name/{uuid,privkey.pem,cert.pem} -// keyset1/manifest/project-name/sudi/host-serial/{uuid,privkey.pem,cert.pem} +// +// keyset1/manifest/project-name/{uuid,privkey.pem,cert.pem} +// keyset1/manifest/project-name/sudi/host-serial/{uuid,privkey.pem,cert.pem} func doGenSudi(ctx *cli.Context) error { args := ctx.Args() if len(args) != 2 && len(args) != 3 { @@ -90,7 +91,6 @@ func doGenSudi(ctx *cli.Context) error { return errors.Wrapf(err, "Failed creating new SUDI directory") } - if err := SignCert(&certTmpl, caCert, caKey, snPath); err != nil { os.RemoveAll(snPath) return errors.Wrapf(err, "Failed creating new SUDI keypair") @@ -134,7 +134,7 @@ func doListSudi(ctx *cli.Context) error { } dir := filepath.Join(projPath, "sudi") - serials, err := os.ReadDir(dir) + serials, err := os.ReadDir(dir) if err != nil { return fmt.Errorf("Failed reading sudi directory %q: %w", dir, err) } diff --git a/cmd/trust/utils.go b/cmd/trust/utils.go index 5b46e3d..e1d1811 100644 --- a/cmd/trust/utils.go +++ b/cmd/trust/utils.go @@ -6,16 +6,16 @@ import ( "crypto/sha1" "crypto/x509" "crypto/x509/pkix" - "encoding/pem" "encoding/hex" "encoding/json" + "encoding/pem" "fmt" "io" "math/big" "os" "path/filepath" - "time" "strings" + "time" "github.com/google/uuid" "github.com/pkg/errors" @@ -438,15 +438,7 @@ func createPCR7Index(pcr7Val []byte) (string, error) { } func extractPubkey(certPath string) (*rsa.PublicKey, error) { - certPEM, err := os.ReadFile(certPath) - if err != nil { - return nil, err - } - block, _ := pem.Decode([]byte(certPEM)) - if block == nil { - return nil, fmt.Errorf("Failed to decode the certificate (%q)", certPath) - } - parsedCert, err := x509.ParseCertificate(block.Bytes) + parsedCert, err := readCertificateFromFile(certPath) if err != nil { return nil, err } @@ -490,9 +482,9 @@ func addPcr7data(keysetName string, pdata pcr7Data) error { var tpmpolAdminpubkey, tpmpolLukspubkey *rsa.PublicKey var jsonInfo []byte type PCR7info struct { - Key string `json:"key"` + Key string `json:"key"` KeyType string `json:"key_type"` - Date string `json:"est_date"` + Date string `json:"est_date"` Comment string `json:"comment"` } @@ -522,7 +514,7 @@ func addPcr7data(keysetName string, pdata pcr7Data) error { pcr7dataPath := filepath.Join(keysetPath, "pcr7data/policy-2") if !PathExists(pcr7dataPath) { err = os.MkdirAll(keysetPath, 0750) - if err != nil { + if err != nil { return err } } else { @@ -554,7 +546,7 @@ func addPcr7data(keysetName string, pdata pcr7Data) error { } tpmpolLukspubkey, err = extractPubkey(filepath.Join(keysetPath, "tpmpol-luks/cert.pem")) if err != nil { - return err + return err } err = savePubkeytoFile(tpmpolLukspubkey, filepath.Join(pcr7dataPubkeys, "luks-snakeoil.pem")) if err != nil { @@ -589,18 +581,18 @@ func addPcr7data(keysetName string, pdata pcr7Data) error { date := time.Now() formatted := date.Format("2006-01-02") timestamp := strings.ReplaceAll(formatted, "-", "") - info := &PCR7info{Key: keysetName, KeyType: pcr, Date: timestamp, Comment: "mos"+" "+keysetName} + info := &PCR7info{Key: keysetName, KeyType: pcr, Date: timestamp, Comment: "mos" + " " + keysetName} jsonInfo, err = json.Marshal(info) if err != nil { return err } if err = os.WriteFile(jsonFile, jsonInfo, 0644); err != nil { - return err + return err } // write out info switch pcr { - case "limited" : + case "limited": pcrFile := filepath.Join(indexdir, "pcr_limited.bin") if err = os.WriteFile(pcrFile, pdata.limited, 0644); err != nil { return err @@ -613,7 +605,7 @@ func addPcr7data(keysetName string, pdata pcr7Data) error { if err = os.WriteFile(pcrFile, pdata.production, 0644); err != nil { return err } - case "tpm" : + case "tpm": // Create policy file and Sign the policy policyFile := filepath.Join(indexdir, "tpm_passwd.policy.signed") if err = os.WriteFile(policyFile, pdata.passwdPolicyDigest, 0644); err != nil { @@ -623,7 +615,7 @@ func addPcr7data(keysetName string, pdata pcr7Data) error { if err = trust.Sign(policyFile, policyFile, signingKey); err != nil { return err } - case "production" : + case "production": // Sign the policy policyFile := filepath.Join(indexdir, "tpm_luks.policy.signed") if err = os.WriteFile(policyFile, pdata.luksPolicyDigest, 0644); err != nil { @@ -633,7 +625,7 @@ func addPcr7data(keysetName string, pdata pcr7Data) error { if err = trust.Sign(policyFile, policyFile, signingKey); err != nil { return err } - default : + default: return errors.New("Unrecognized uki key") } } diff --git a/cmd/trust/verify.go b/cmd/trust/verify.go index 5884631..bf037a1 100644 --- a/cmd/trust/verify.go +++ b/cmd/trust/verify.go @@ -9,17 +9,17 @@ import ( ) var verifyCmd = cli.Command{ - Name: "verify", + Name: "verify", Usage: "Verify a digital Signature", Subcommands: []cli.Command{ cli.Command{ - Name: "efi", - Action: doVerifyEFI, - Usage: "verify a signed efi binary", + Name: "efi", + Action: doVerifyEFI, + Usage: "verify a signed efi binary", ArgsUsage: "", Flags: []cli.Flag{ cli.StringFlag{ - Name: "cert", + Name: "cert", Usage: "The X509 certificate to verify signature.", }, }, diff --git a/pkg/trust/artifacts.go b/pkg/trust/artifacts.go index 11d01a3..98d7c41 100644 --- a/pkg/trust/artifacts.go +++ b/pkg/trust/artifacts.go @@ -307,7 +307,7 @@ func findSection(lines []string, which string) (int64, int64, bool) { } func extractObj(objdump []string, dir string, piece string) error { - outName := filepath.Join(dir, piece + ".out") + outName := filepath.Join(dir, piece+".out") offset, size, found := findSection(objdump, piece) if !found { return fmt.Errorf("Symbol %s not found", piece) @@ -387,7 +387,7 @@ func ReplaceManifestCert(dir, newCert string) (string, error) { } err := RunCommand("objcopy", - "--add-section=.initrd=" + initrdgz, + "--add-section=.initrd="+initrdgz, "--change-section-vma=.initrd=0x3000000", k2, kret) if err != nil { diff --git a/pkg/trust/cert.go b/pkg/trust/cert.go index 34faa62..83c4017 100644 --- a/pkg/trust/cert.go +++ b/pkg/trust/cert.go @@ -10,8 +10,8 @@ import ( "os" "github.com/foxboron/go-uefi/efi/pecoff" - "github.com/foxboron/go-uefi/efi/util" "github.com/foxboron/go-uefi/efi/pkcs7" + "github.com/foxboron/go-uefi/efi/util" ) // VerifyCert checks that the product cert was signed by the @@ -145,7 +145,7 @@ func SignEFI(sourcePath, signedPath, keyPath, certPath string) error { // Get the key to use for signing privkey, err := util.ReadKeyFromFile(keyPath) if err != nil { - return fmt.Errorf("Failed reading (%q): %w", keyPath, err) + return fmt.Errorf("Failed reading (%q): %w", keyPath, err) } cert, err := util.ReadCertFromFile(certPath) if err != nil { diff --git a/pkg/trust/computepcr7.go b/pkg/trust/computepcr7.go index c46860a..854e26e 100644 --- a/pkg/trust/computepcr7.go +++ b/pkg/trust/computepcr7.go @@ -18,6 +18,7 @@ import ( const ShimLockGUID = "605dab50-e046-4300-abb6-3dd810dd8b23" const ShimVendordbGUID = "00000000-0000-0000-0000-000000000000" const SBAT = "sbat,1,2021030218\012" + // Using DBX data from current ovmf_vars.fd in bootkit. // Revisit if ovmf or dbx changes. We need to eventually manage dbx. const DBX = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" @@ -49,7 +50,7 @@ func getCertGUID(guidfile string) (efi.GUID, error) { return efi.GUID{}, fmt.Errorf("Failed to read %q: (%w)", guidfile, err) } certGuid, err := efi.DecodeGUIDString(string(cGuid)) - if err != nil { + if err != nil { return efi.GUID{}, fmt.Errorf("Failed to decode the guid in %q: (%w)", guidfile, err) } @@ -183,14 +184,14 @@ func getHash(unicodeName string, varGuid efi.GUID, keysetPath string) ([]byte, e func ComputePCR7(keysetName string) ([]byte, []byte, []byte, error) { var pcr7Val = []byte{00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, - 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, - 00, 00, 00, 00, 00, 00, 00, 00, 00, 00} + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00} // List of uefi Secure boot vars that get measured. // It includes certs that get measured at boot. UKI certs are measured // separately since we have 3 possible. Also measured in this order. - var uefiMeasured = []string{"SecureBoot", "PK", "KEK", "db", "dbx","separator", - "shim-cert", "SbatLevel", "MokListTrusted" } + var uefiMeasured = []string{"SecureBoot", "PK", "KEK", "db", "dbx", "separator", + "shim-cert", "SbatLevel", "MokListTrusted"} shimLockGuid, err := efi.DecodeGUIDString(ShimLockGUID) if err != nil { diff --git a/pkg/trust/tpm2.go b/pkg/trust/tpm2.go index c717c8a..3e962fe 100644 --- a/pkg/trust/tpm2.go +++ b/pkg/trust/tpm2.go @@ -40,16 +40,16 @@ func init() { } type tpm2V3Context struct { - dataDir string // our data directory under which we keep files - keyClass string // release, dev, or snakeoil - adminPwd string // provisioned tpm admin password - pubkeyName string // pubkeyname from tpm2_loadexternal - pubkeyContext string // pubkeycontext from tpm2_loadexternal - tmpDir string // directory for tpm2 sessions and other io - sessionFile string - Keyctx string // pathname to file from tpm2_createprimary - PlainPart *DiskPart // Disk partition with plaintext provisioned data - CryptPart *DiskPart // Disk partition with encrypted provisioned data + dataDir string // our data directory under which we keep files + keyClass string // release, dev, or snakeoil + adminPwd string // provisioned tpm admin password + pubkeyName string // pubkeyname from tpm2_loadexternal + pubkeyContext string // pubkeycontext from tpm2_loadexternal + tmpDir string // directory for tpm2 sessions and other io + sessionFile string + Keyctx string // pathname to file from tpm2_createprimary + PlainPart *DiskPart // Disk partition with plaintext provisioned data + CryptPart *DiskPart // Disk partition with encrypted provisioned data } type DiskPart struct { @@ -140,11 +140,13 @@ func getPoldir(pdir string) string { } // ChooseSignData: assumes that someone has placed the pcr7data -// under SignDataDir (/pcr7data). Finds the pcr7 data for the -// running host+shim+kernel. +// +// under SignDataDir (/pcr7data). Finds the pcr7 data for the +// running host+shim+kernel. +// // Returns: -// 1. the signdata directory name for this host's pcr7 value -// 2. the type of key this was signed by (e.g. "production") +// 1. the signdata directory name for this host's pcr7 value +// 2. the type of key this was signed by (e.g. "production") func ChooseSignData() (string, string, error) { polDir := getPoldir(SignDataDir) if polDir == "" { @@ -249,9 +251,9 @@ func NewTpm2() (*tpm2V3Context, error) { } t = &tpm2V3Context{ - dataDir: dataDir, - tmpDir: tmpd, - keyClass: keyClass, + dataDir: dataDir, + tmpDir: tmpd, + keyClass: keyClass, } return t, nil } @@ -306,7 +308,7 @@ func setupFactory() (string, error) { } err = os.Mkdir(dest, 0700) - if err != nil { + if err != nil { return dest, fmt.Errorf("Could not create %s on tmpfs: %w", dest, err) } return dest, nil @@ -322,6 +324,7 @@ func (t *tpm2V3Context) Close() { } type KeyType string + const ( limitedKey KeyType = "limited" productionKey KeyType = "production" diff --git a/pkg/trust/tpmpolicy.go b/pkg/trust/tpmpolicy.go index 71718e9..3cf1800 100644 --- a/pkg/trust/tpmpolicy.go +++ b/pkg/trust/tpmpolicy.go @@ -40,7 +40,7 @@ func GenLuksPolicy(prodPcr7 []byte, policyVersion string) ([]byte, error) { // Create a tpm2.NVPublic structure that resembles what we would have // done via an nvwrite of the policy version to the index. // Include TPMA_NV_WRITTEN attribute indicating the index has been written to. - nvpub := tpm2.NVPublic{Index: tpm2.Handle(TPM2IndexEAVersion), NameAlg: tpm2.HashAlgorithmSHA256, Attrs: tpm2.NVTypeOrdinary.WithAttrs(tpm2.AttrNVOwnerWrite|tpm2.AttrNVOwnerRead|tpm2.AttrNVAuthRead|tpm2.AttrNVWritten), Size: 4} + nvpub := tpm2.NVPublic{Index: tpm2.Handle(TPM2IndexEAVersion), NameAlg: tpm2.HashAlgorithmSHA256, Attrs: tpm2.NVTypeOrdinary.WithAttrs(tpm2.AttrNVOwnerWrite | tpm2.AttrNVOwnerRead | tpm2.AttrNVAuthRead | tpm2.AttrNVWritten), Size: 4} trial := util.ComputeAuthPolicy(tpm2.HashAlgorithmSHA256) trial.PolicyPCR(pcrDigest, tpm2.PCRSelectionList{{Hash: tpm2.HashAlgorithmSHA256, Select: []int{7}}}) diff --git a/pkg/trust/utils.go b/pkg/trust/utils.go index bd1205f..5782b8e 100644 --- a/pkg/trust/utils.go +++ b/pkg/trust/utils.go @@ -85,7 +85,7 @@ func genPassphrase(nchars int) (string, error) { // trust-. So if we want 39 or 40 characters, request (39-6)/2+1 = 17 // bytes, giving us 136 bits of randomness. - nbytes := (nchars - 6) / 2 + 1 + nbytes := (nchars-6)/2 + 1 rand, err := HWRNGRead(nbytes) if err != nil { return "", err @@ -157,11 +157,11 @@ func RunWithStdall(stdinString string, args ...string) (string, string, error) { // Run: run a command. Return the output and an error if any. func Run(args ...string) (string, error) { cmd := exec.Command(args[0], args[1:]...) - output, err := cmd.CombinedOutput() - if err != nil { - return string(output), errors.Wrapf(err, "Failed running %v", args) - } - return string(output), nil + output, err := cmd.CombinedOutput() + if err != nil { + return string(output), errors.Wrapf(err, "Failed running %v", args) + } + return string(output), nil } func RunCommand(args ...string) error {