package identity_test import ( "crypto/ed25519" "crypto/rand" "encoding/hex" "errors" "testing" "github.com/drjones/quantum-arcade/pkg/identity" ) func newKey(t *testing.T) (string, ed25519.PrivateKey) { t.Helper() pub, priv, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatal(err) } return hex.EncodeToString(pub), priv } func TestValidSignatureAuthenticates(t *testing.T) { a := identity.NewAuthenticator() pubHex, priv := newKey(t) nonceHex, err := a.Challenge(pubHex) if err != nil { t.Fatal(err) } nonce, _ := hex.DecodeString(nonceHex) sig := ed25519.Sign(priv, nonce) if err := a.Verify(pubHex, hex.EncodeToString(sig)); err != nil { t.Fatalf("valid signature rejected: %v", err) } } func TestWrongKeyCannotAuthenticate(t *testing.T) { a := identity.NewAuthenticator() pubHex, _ := newKey(t) _, otherPriv := newKey(t) nonceHex, _ := a.Challenge(pubHex) nonce, _ := hex.DecodeString(nonceHex) sig := ed25519.Sign(otherPriv, nonce) if err := a.Verify(pubHex, hex.EncodeToString(sig)); !errors.Is(err, identity.ErrBadSignature) { t.Fatalf("got %v, want ErrBadSignature", err) } } // A captured signature must not work twice. func TestChallengeIsSingleUse(t *testing.T) { a := identity.NewAuthenticator() pubHex, priv := newKey(t) nonceHex, _ := a.Challenge(pubHex) nonce, _ := hex.DecodeString(nonceHex) sigHex := hex.EncodeToString(ed25519.Sign(priv, nonce)) if err := a.Verify(pubHex, sigHex); err != nil { t.Fatal(err) } if err := a.Verify(pubHex, sigHex); !errors.Is(err, identity.ErrUnknownChallenge) { t.Fatalf("replay succeeded or gave %v, want ErrUnknownChallenge", err) } } func TestMalformedKeyRejected(t *testing.T) { a := identity.NewAuthenticator() if _, err := a.Challenge("not-hex"); !errors.Is(err, identity.ErrBadPublicKey) { t.Fatalf("got %v, want ErrBadPublicKey", err) } if _, err := a.Challenge("aabb"); !errors.Is(err, identity.ErrBadPublicKey) { t.Fatalf("short key: got %v, want ErrBadPublicKey", err) } } func TestVerifyWithoutChallengeFails(t *testing.T) { a := identity.NewAuthenticator() pubHex, priv := newKey(t) sig := ed25519.Sign(priv, []byte("anything")) if err := a.Verify(pubHex, hex.EncodeToString(sig)); !errors.Is(err, identity.ErrUnknownChallenge) { t.Fatalf("got %v, want ErrUnknownChallenge", err) } }