aboutsummaryrefslogtreecommitdiff
path: root/verify/core/verification.go
diff options
context:
space:
mode:
Diffstat (limited to 'verify/core/verification.go')
-rw-r--r--verify/core/verification.go165
1 files changed, 165 insertions, 0 deletions
diff --git a/verify/core/verification.go b/verify/core/verification.go
new file mode 100644
index 0000000..289ce1e
--- /dev/null
+++ b/verify/core/verification.go
@@ -0,0 +1,165 @@
+package core
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "os"
+ "strings"
+
+ "aead.dev/minisign"
+ "github.com/axtloss/fsverify/config"
+ "github.com/tarm/serial"
+)
+
+// fileReadKey reads the public minisign key from a file specified in config.KeyLocation.
+func fileReadKey() (string, error) {
+ if _, err := os.Stat(config.KeyLocation); os.IsNotExist(err) {
+ return "", fmt.Errorf("Key location %s does not exist", config.KeyLocation)
+ }
+ file, err := os.Open(config.KeyLocation)
+ if err != nil {
+ return "", err
+ }
+ defer file.Close()
+ // A public key is never longer than 56 bytes
+ key := make([]byte, 56)
+ reader := bufio.NewReader(file)
+ n, err := reader.Read(key)
+ if n != 56 {
+ return "", fmt.Errorf("Key does not match expected key size. Expected 56, got %d", n)
+ }
+ if err != nil {
+ return "", err
+ }
+ return string(key), nil
+}
+
+// serialReadKey reads the public minisign key from a usb tty specified in config.KeyLocation.
+func serialReadKey() (string, error) {
+ // Since the usb serial is tested with an arduino
+ // it is assumed that the tty device does not always exist
+ // and can be manually plugged in by the user
+ if _, err := os.Stat(config.KeyLocation); !os.IsNotExist(err) {
+ fmt.Println("Reconnect arduino now")
+ for true {
+ if _, err := os.Stat(config.KeyLocation); os.IsNotExist(err) {
+ break
+ }
+ }
+ } else {
+ fmt.Println("Connect arduino now")
+ }
+ for true {
+ if _, err := os.Stat(config.KeyLocation); !os.IsNotExist(err) {
+ break
+ }
+ }
+ fmt.Println("Arduino connected")
+ c := &serial.Config{Name: config.KeyLocation, Baud: 9600}
+ s, err := serial.OpenPort(c)
+ if err != nil {
+ return "", err
+ }
+
+ key := ""
+ for true {
+ buf := make([]byte, 128)
+ n, err := s.Read(buf)
+ if err != nil {
+ return "", err
+ }
+ defer s.Close()
+ key = key + fmt.Sprintf("%q", buf[:n])
+ // ensure that two tab sequences are read
+ // meaning that the entire key has been captured
+ // since the key is surrounded by a tab sequence
+ if strings.Count(key, "\\t") == 2 {
+ break
+ }
+ }
+ key = strings.ReplaceAll(key, "\\t", "")
+ key = strings.ReplaceAll(key, "\"", "")
+ if len(key) != 56 {
+ return "", fmt.Errorf("Key does not match expected key size. Expected 56, got %d", len(key))
+ }
+ return key, nil
+}
+
+// ReadKey is a wrapper function to call the proper readKey function according to config.KeyStore.
+func ReadKey() (string, error) {
+ switch config.KeyStore {
+ case 0:
+ return fileReadKey()
+ case 1:
+ return fileReadKey()
+ case 2:
+ return "", nil // TPM
+ case 3:
+ return serialReadKey()
+ }
+ return "", nil
+}
+
+// ReadBlock reads a data area of a bytes.Reader specified in the given node.
+// It additionally verifies that the amount of bytes read equal the wanted amount and returns an error if this is not the case.
+func ReadBlock(node Node, part *bytes.Reader, totalReadBlocks int) ([]byte, int, error) {
+ if node.BlockEnd-node.BlockStart < 0 {
+ return []byte{}, -1, fmt.Errorf("tried creating byte slice with negative length. %d to %d total %d\n", node.BlockStart, node.BlockEnd, node.BlockEnd-node.BlockStart)
+ } else if node.BlockEnd-node.BlockStart > 2000 {
+ return []byte{}, -1, fmt.Errorf("tried creating byte slice with length over 2000. %d to %d total %d\n", node.BlockStart, node.BlockEnd, node.BlockEnd-node.BlockStart)
+ }
+ block := make([]byte, node.BlockEnd-node.BlockStart)
+ blockSize := node.BlockEnd - node.BlockStart
+ _, err := part.Seek(int64(node.BlockStart), 0)
+ if err != nil {
+ return []byte{}, -1, err
+ }
+ n, err := part.Read(block)
+ if err != nil {
+ return block, -1, err
+ } else if n != blockSize {
+ return block, -1, fmt.Errorf("Did not read correct amount of bytes. Expected: %d, Got: %d", blockSize, n)
+ }
+ return block, totalReadBlocks + 1, err
+}
+
+// VerifySignature verifies the database using a given signature and public key.
+func VerifySignature(key string, signature string, database string) (bool, error) {
+ var pk minisign.PublicKey
+ if err := pk.UnmarshalText([]byte(key)); err != nil {
+ return false, err
+ }
+
+ data, err := os.ReadFile(database)
+ if err != nil {
+ return false, err
+ }
+
+ return minisign.Verify(pk, data, []byte(signature)), nil
+}
+
+// VerifyBlock verifies a byte slice with the hash in a given Node.
+func VerifyBlock(block []byte, node Node) error {
+ calculatedBlockHash, err := CalculateBlockHash(block)
+ if err != nil {
+ return err
+ }
+ wantedBlockHash := node.BlockSum
+ if strings.Compare(calculatedBlockHash, strings.TrimSpace(wantedBlockHash)) == 0 {
+ return nil
+ }
+ return fmt.Errorf("Node %s ranging from %d to %d does not match block. Expected %s, got %s.", node.PrevNodeSum, node.BlockStart, node.BlockEnd, wantedBlockHash, calculatedBlockHash)
+}
+
+// VerifyNode verifies that the current Node is valid by matching the checksum of it with the PrevNodeSum field of the next node.
+func VerifyNode(node Node, nextNode Node) error {
+ nodeHash, err := calculateStringHash(fmt.Sprintf("%d%d%s%s", node.BlockStart, node.BlockEnd, node.BlockSum, node.PrevNodeSum))
+ if err != nil {
+ return err
+ }
+ if strings.Compare(nodeHash, nextNode.PrevNodeSum) != 0 {
+ return fmt.Errorf("Node %s is not valid!", node.PrevNodeSum)
+ }
+ return nil
+}