Monorepo for Tangled tangled.org
2

Configure Feed

Select the types of activity you want to include in your feed.

1package crypto 2 3import ( 4 "bytes" 5 "crypto/ed25519" 6 "crypto/rand" 7 "strings" 8 "testing" 9 10 "github.com/hiddeco/sshsig" 11 "golang.org/x/crypto/ssh" 12) 13 14// testKey generates an ephemeral ed25519 key pair and returns the ssh.Signer 15// and the public key in authorized_keys format. 16func testKey(t *testing.T) (ssh.Signer, []byte) { 17 t.Helper() 18 _, priv, err := ed25519.GenerateKey(rand.Reader) 19 if err != nil { 20 t.Fatalf("generate ed25519 key: %v", err) 21 } 22 signer, err := ssh.NewSignerFromKey(priv) 23 if err != nil { 24 t.Fatalf("create signer: %v", err) 25 } 26 return signer, ssh.MarshalAuthorizedKey(signer.PublicKey()) 27} 28 29// testSign signs payload with signer using the same parameters as VerifySignature 30// expects (SHA-512, "git" namespace) and returns the armored signature. 31func testSign(t *testing.T, signer ssh.Signer, payload []byte) []byte { 32 t.Helper() 33 sig, err := sshsig.Sign(bytes.NewReader(payload), signer, sshsig.HashSHA512, "git") 34 if err != nil { 35 t.Fatalf("sign payload: %v", err) 36 } 37 return sshsig.Armor(sig) 38} 39 40func TestSSHFingerprint(t *testing.T) { 41 t.Run("valid key returns SHA256 fingerprint", func(t *testing.T) { 42 _, pubKeyBytes := testKey(t) 43 fp, err := SSHFingerprint(string(pubKeyBytes)) 44 if err != nil { 45 t.Fatalf("unexpected error: %v", err) 46 } 47 if !strings.HasPrefix(fp, "SHA256:") { 48 t.Errorf("fingerprint %q does not start with SHA256:", fp) 49 } 50 }) 51 52 t.Run("same key returns identical fingerprint", func(t *testing.T) { 53 _, pubKeyBytes := testKey(t) 54 fp1, _ := SSHFingerprint(string(pubKeyBytes)) 55 fp2, _ := SSHFingerprint(string(pubKeyBytes)) 56 if fp1 != fp2 { 57 t.Errorf("fingerprint not deterministic: %q != %q", fp1, fp2) 58 } 59 }) 60 61 t.Run("different keys return different fingerprints", func(t *testing.T) { 62 _, pub1 := testKey(t) 63 _, pub2 := testKey(t) 64 fp1, _ := SSHFingerprint(string(pub1)) 65 fp2, _ := SSHFingerprint(string(pub2)) 66 if fp1 == fp2 { 67 t.Error("different keys produced the same fingerprint") 68 } 69 }) 70 71 t.Run("malformed key returns error", func(t *testing.T) { 72 _, err := SSHFingerprint("not a valid ssh public key") 73 if err == nil { 74 t.Error("expected error for malformed key") 75 } 76 }) 77} 78 79func TestVerifySignature(t *testing.T) { 80 signer, pubKeyBytes := testKey(t) 81 payload := []byte("test payload") 82 armoredSig := testSign(t, signer, payload) 83 84 t.Run("valid signature verifies successfully", func(t *testing.T) { 85 err, ok := VerifySignature(pubKeyBytes, armoredSig, payload) 86 if err != nil { 87 t.Errorf("unexpected error: %v", err) 88 } 89 if !ok { 90 t.Error("expected ok=true for valid signature") 91 } 92 }) 93 94 t.Run("malformed public key returns error", func(t *testing.T) { 95 err, ok := VerifySignature([]byte("not a valid key"), armoredSig, payload) 96 if err == nil { 97 t.Error("expected error for malformed public key") 98 } 99 if ok { 100 t.Error("expected ok=false") 101 } 102 }) 103 104 t.Run("malformed signature returns error", func(t *testing.T) { 105 err, ok := VerifySignature(pubKeyBytes, []byte("not a valid signature"), payload) 106 if err == nil { 107 t.Error("expected error for malformed signature") 108 } 109 if ok { 110 t.Error("expected ok=false") 111 } 112 }) 113 114 t.Run("tampered payload fails verification", func(t *testing.T) { 115 err, ok := VerifySignature(pubKeyBytes, armoredSig, []byte("tampered")) 116 if err == nil { 117 t.Error("expected error for tampered payload") 118 } 119 if ok { 120 t.Error("expected ok=false for tampered payload") 121 } 122 }) 123 124 t.Run("wrong public key fails verification", func(t *testing.T) { 125 _, otherPubKey := testKey(t) 126 err, ok := VerifySignature(otherPubKey, armoredSig, payload) 127 if err == nil { 128 t.Error("expected error for wrong public key") 129 } 130 if ok { 131 t.Error("expected ok=false for wrong public key") 132 } 133 }) 134}