+103
cmd/verifysig/main.go
+103
cmd/verifysig/main.go
···
···
1
+
package main
2
+
3
+
import (
4
+
"flag"
5
+
"fmt"
6
+
"io"
7
+
"os"
8
+
"strings"
9
+
10
+
"tangled.sh/tangled.sh/core/crypto"
11
+
)
12
+
13
+
func parseCommitObject(commitData string) (string, string, error) {
14
+
lines := strings.Split(commitData, "\n")
15
+
16
+
var payloadLines []string
17
+
var signatureLines []string
18
+
var inSignature bool
19
+
var foundSignature bool
20
+
21
+
for _, line := range lines {
22
+
if strings.HasPrefix(line, "gpgsig ") {
23
+
foundSignature = true
24
+
inSignature = true
25
+
// remove 'gpgsig' prefix
26
+
sigLine := strings.TrimPrefix(line, "gpgsig ")
27
+
signatureLines = append(signatureLines, sigLine)
28
+
continue
29
+
}
30
+
31
+
if inSignature {
32
+
// check if this line is part of the signature (starts with space)
33
+
if strings.HasPrefix(line, " ") {
34
+
// remove the leading space and add to signature
35
+
sigLine := strings.TrimPrefix(line, " ")
36
+
signatureLines = append(signatureLines, sigLine)
37
+
continue
38
+
} else {
39
+
// end of signature block
40
+
inSignature = false
41
+
// this line is part of payload, so add it
42
+
payloadLines = append(payloadLines, line)
43
+
}
44
+
} else {
45
+
// regular payload line
46
+
payloadLines = append(payloadLines, line)
47
+
}
48
+
}
49
+
50
+
if !foundSignature {
51
+
return "", commitData, nil // no signature found, return empty signature and full data as payload
52
+
}
53
+
54
+
signature := strings.Join(signatureLines, "\n")
55
+
payload := strings.Join(payloadLines, "\n")
56
+
57
+
return signature, payload, nil
58
+
}
59
+
60
+
func main() {
61
+
var pubkeyPath string
62
+
flag.StringVar(&pubkeyPath, "pubkey", "", "Path to the public key file")
63
+
flag.Parse()
64
+
65
+
var pubKey []byte
66
+
var err error
67
+
if pubkeyPath != "" {
68
+
pubKey, err = os.ReadFile(pubkeyPath)
69
+
if err != nil {
70
+
fmt.Fprintf(os.Stderr, "error reading public key file: %v\n", err)
71
+
os.Exit(1)
72
+
}
73
+
}
74
+
75
+
input, err := io.ReadAll(os.Stdin)
76
+
if err != nil {
77
+
fmt.Fprintf(os.Stderr, "error reading from stdin: %v\n", err)
78
+
os.Exit(1)
79
+
}
80
+
81
+
commitData := string(input)
82
+
83
+
signature, payload, err := parseCommitObject(commitData)
84
+
if err != nil {
85
+
fmt.Fprintf(os.Stderr, "error parsing commit: %v\n", err)
86
+
os.Exit(1)
87
+
}
88
+
89
+
fmt.Println("signature")
90
+
fmt.Println(signature)
91
+
fmt.Println()
92
+
fmt.Println("payload:")
93
+
fmt.Println(payload)
94
+
95
+
err, ok := crypto.VerifySignature(pubKey, []byte(signature), []byte(payload))
96
+
if err != nil {
97
+
fmt.Fprintf(os.Stderr, "%v\n", err)
98
+
os.Exit(1)
99
+
}
100
+
if ok {
101
+
fmt.Println("ok")
102
+
}
103
+
}
+4
-1
crypto/verify.go
+4
-1
crypto/verify.go
···
24
}
25
26
buf := bytes.NewBuffer(payload)
27
+
// we use sha-512 because ed25519 keys require it internally; rsa keys support
28
+
// multiple algorithms but sha-512 is most secure, and git's ssh signing defaults
29
+
// to sha-512 for all key types anyway.
30
+
err = sshsig.Verify(buf, sig, pub, sshsig.HashSHA512, "git")
31
return err, err == nil
32
}
33