Monorepo for Tangled tangled.org

crypto: add tests for VerifySignature and SSHFingerprint #1233

open opened by matias.tngl.sh targeting master from matias.tngl.sh/core: crypto-test-coverage

Add test coverage for the two exported functions in the crypto package.

Tests generate an ephemeral ed25519 key pair at runtime to avoid committing key material as fixtures. Coverage targets all code paths:

  • SSHFingerprint: valid key, malformed key
  • VerifySignature: invalid pubkey, invalid signature, tampered payload, and a valid round-trip
Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:wtmr5brxfbwmb666krk4y75r/sh.tangled.repo.pull/3mi3hvd342522
+134
Diff #0
+134
crypto/verify_test.go
··· 1 + package crypto 2 + 3 + import ( 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. 16 + func 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. 31 + func 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 + 40 + func 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 + 79 + func 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 + }

History

1 round 0 comments
sign up or login to add to the discussion
matias.tngl.sh submitted #0
1 commit
expand
crypto: add tests for VerifySignature and SSHFingerprint
no conflicts, ready to merge
expand 0 comments