Skip to content

Commit

Permalink
keys: ensure we compare the input/output files
Browse files Browse the repository at this point in the history
We only used the path for this instead of comparing the authenticode
hashes.

Signed-off-by: Morten Linderud <[email protected]>
  • Loading branch information
Foxboron committed Aug 12, 2024
1 parent b6f54ae commit 824fb03
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 25 deletions.
9 changes: 2 additions & 7 deletions backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,16 +180,11 @@ func (k *KeyHierarchy) VerifyFile(hier hierarchy.Hierarchy, r io.ReaderAt) (bool
return ok, nil
}

func (k *KeyHierarchy) SignFile(hier hierarchy.Hierarchy, r io.ReaderAt) ([]byte, error) {
func (k *KeyHierarchy) SignFile(hier hierarchy.Hierarchy, peBinary *authenticode.PECOFFBinary) ([]byte, error) {
kk := k.GetKeyBackend(hier.Efivar())
signer := kk.Signer()

peBinary, err := authenticode.Parse(r)
if err != nil {
return nil, err
}

_, err = peBinary.Sign(signer, kk.Certificate())
_, err := peBinary.Sign(signer, kk.Certificate())
if err != nil {
return nil, err
}
Expand Down
65 changes: 47 additions & 18 deletions keys.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package sbctl

import (
"bytes"
"crypto"
"errors"
"fmt"
"os"
Expand Down Expand Up @@ -32,6 +34,8 @@ func VerifyFile(state *config.State, kh *backend.KeyHierarchy, ev hierarchy.Hier
var ErrAlreadySigned = errors.New("already signed file")

func SignFile(state *config.State, kh *backend.KeyHierarchy, ev hierarchy.Hierarchy, file, output string) error {
// Check to see if input and output binary is the same
var same bool

// Make sure that output is always populated by atleast the file path
if output == "" {
Expand All @@ -43,23 +47,6 @@ func SignFile(state *config.State, kh *backend.KeyHierarchy, ev hierarchy.Hierar
return fmt.Errorf("%s does not exist", file)
}

// Let's check if we have signed it already AND the original file hasn't changed
ok, err := VerifyFile(state, kh, ev, output)
if errors.Is(err, os.ErrNotExist) && (file != output) {
// if the file does not exist and file is not the same as output
// then we just catch the error and continue. This is expected
// behaviour
} else if errors.Is(err, authenticode.ErrNoValidSignatures) {
// If we tried to verify the file, but it has signatures but nothing signed
// by our key, we catch the error and continue.
} else if err != nil {
return err
}

if ok {
return ErrAlreadySigned
}

// We want to write the file back with correct permissions
si, err := state.Fs.Stat(file)
if err != nil {
Expand All @@ -72,7 +59,49 @@ func SignFile(state *config.State, kh *backend.KeyHierarchy, ev hierarchy.Hierar
}
defer peFile.Close()

b, err := kh.SignFile(ev, peFile)
inputBinary, err := authenticode.Parse(peFile)
if err != nil {
return err
}

// Check if the files are identical
if file != output {
outputFile, err := state.Fs.Open(output)
if err != nil {
return err
}
defer outputFile.Close()
outputBinary, err := authenticode.Parse(outputFile)
if err != nil {
return err
}
b := outputBinary.Hash(crypto.SHA256)
bb := inputBinary.Hash(crypto.SHA256)
if bytes.Equal(b, bb) {
same = true
}
}

if file == output {
same = true
}

// Let's check if we have signed it already AND the original file hasn't changed
// TODO: This will run authenticode.Parse again, *and* open the file
// this should be refactored to be nicer
ok, err := VerifyFile(state, kh, ev, output)
if errors.Is(err, authenticode.ErrNoValidSignatures) {
// If we tried to verify the file, but it has signatures but nothing signed
// by our key, we catch the error and continue.
} else if ok && same {
// If already signed, and the input/output binaries are identical,
// we can just assume everything is fine.
return ErrAlreadySigned
} else if err != nil {
return err
}

b, err := kh.SignFile(ev, inputBinary)
if err != nil {
return err
}
Expand Down

0 comments on commit 824fb03

Please sign in to comment.