+70
crypto/verify.go
+70
crypto/verify.go
···
1
+
package crypto
2
+
3
+
import (
4
+
"bytes"
5
+
"crypto/sha256"
6
+
"encoding/base64"
7
+
"fmt"
8
+
"strings"
9
+
10
+
"github.com/hiddeco/sshsig"
11
+
"golang.org/x/crypto/ssh"
12
+
"tangled.sh/tangled.sh/core/types"
13
+
)
14
+
15
+
func VerifySignature(pubKey, signature, payload []byte) (error, bool) {
16
+
pub, _, _, _, err := ssh.ParseAuthorizedKey(pubKey)
17
+
if err != nil {
18
+
return fmt.Errorf("failed to parse public key: %w", err), false
19
+
}
20
+
21
+
sig, err := sshsig.Unarmor(signature)
22
+
if err != nil {
23
+
return fmt.Errorf("failed to parse signature: %w", err), false
24
+
}
25
+
26
+
buf := bytes.NewBuffer(payload)
27
+
sshsig.Verify(buf, sig, pub, sshsig.HashSHA256, "git")
28
+
return err, err == nil
29
+
}
30
+
31
+
// VerifyCommitSignature reconstructs the payload used to sign a commit. This is
32
+
// essentially the git cat-file output but without the gpgsig header.
33
+
//
34
+
// Caveats: signature verification will fail on commits with more than one parent,
35
+
// i.e. merge commits, because types.NiceDiff doesn't carry more than one Parent field
36
+
// and we are unable to reconstruct the payload correctly.
37
+
//
38
+
// Ideally this should directly operate on an *object.Commit.
39
+
func VerifyCommitSignature(pubKey string, commit types.NiceDiff) (error, bool) {
40
+
signature := commit.Commit.PGPSignature
41
+
42
+
author := bytes.NewBuffer([]byte{})
43
+
committer := bytes.NewBuffer([]byte{})
44
+
commit.Commit.Author.Encode(author)
45
+
commit.Commit.Committer.Encode(committer)
46
+
47
+
payload := strings.Builder{}
48
+
49
+
fmt.Fprintf(&payload, "tree %s\n", commit.Commit.Tree)
50
+
fmt.Fprintf(&payload, "parent %s\n", commit.Commit.Parent)
51
+
fmt.Fprintf(&payload, "author %s\n", author.String())
52
+
fmt.Fprintf(&payload, "committer %s\n", committer.String())
53
+
if commit.Commit.ChangedId != "" {
54
+
fmt.Fprintf(&payload, "change-id %s\n", commit.Commit.ChangedId)
55
+
}
56
+
fmt.Fprintf(&payload, "\n%s", commit.Commit.Message)
57
+
58
+
return VerifySignature([]byte(pubKey), []byte(signature), []byte(payload.String()))
59
+
}
60
+
61
+
// SSHFingerprint computes the fingerprint of the supplied ssh pubkey.
62
+
func SSHFingerprint(pubKey string) (string, error) {
63
+
pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(pubKey))
64
+
if err != nil {
65
+
return "", err
66
+
}
67
+
68
+
hash := sha256.Sum256(pk.Marshal())
69
+
return "SHA256:" + base64.StdEncoding.EncodeToString(hash[:]), nil
70
+
}
+2
-1
go.mod
+2
-1
go.mod
···
21
21
github.com/go-git/go-git/v5 v5.14.0
22
22
github.com/google/uuid v1.6.0
23
23
github.com/gorilla/sessions v1.4.0
24
+
github.com/hiddeco/sshsig v0.2.0
24
25
github.com/ipfs/go-cid v0.5.0
25
26
github.com/lestrrat-go/jwx/v2 v2.1.6
26
27
github.com/mattn/go-sqlite3 v1.14.24
···
31
32
github.com/urfave/cli/v3 v3.3.3
32
33
github.com/whyrusleeping/cbor-gen v0.3.1
33
34
github.com/yuin/goldmark v1.4.13
35
+
golang.org/x/crypto v0.38.0
34
36
golang.org/x/net v0.39.0
35
37
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da
36
38
tangled.sh/icyphox.sh/atproto-oauth v0.0.0-20250526154904-3906c5336421
···
122
124
go.uber.org/atomic v1.11.0 // indirect
123
125
go.uber.org/multierr v1.11.0 // indirect
124
126
go.uber.org/zap v1.27.0 // indirect
125
-
golang.org/x/crypto v0.38.0 // indirect
126
127
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
127
128
golang.org/x/sync v0.13.0 // indirect
128
129
golang.org/x/sys v0.33.0 // indirect
+2
go.sum
+2
go.sum
···
160
160
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
161
161
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
162
162
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
163
+
github.com/hiddeco/sshsig v0.2.0 h1:gMWllgKCITXdydVkDL+Zro0PU96QI55LwUwebSwNTSw=
164
+
github.com/hiddeco/sshsig v0.2.0/go.mod h1:nJc98aGgiH6Yql2doqH4CTBVHexQA40Q+hMMLHP4EqE=
163
165
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
164
166
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
165
167
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=