package authn import ( "bytes" "crypto/ed25519" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestBuildResponseSigningInputChangesWhenSignedFieldChanges(t *testing.T) { t.Parallel() base := ResponseSigningFields{ ProtocolVersion: "v1", RequestID: "request-123", TimestampMS: 123456789, ResultCode: "ok", PayloadHash: mustSHA256([]byte("payload")), } baseInput := BuildResponseSigningInput(base) tests := []struct { name string mutate func(ResponseSigningFields) ResponseSigningFields }{ { name: "protocol version", mutate: func(fields ResponseSigningFields) ResponseSigningFields { fields.ProtocolVersion = "v2" return fields }, }, { name: "request id", mutate: func(fields ResponseSigningFields) ResponseSigningFields { fields.RequestID = "request-456" return fields }, }, { name: "timestamp", mutate: func(fields ResponseSigningFields) ResponseSigningFields { fields.TimestampMS++ return fields }, }, { name: "result code", mutate: func(fields ResponseSigningFields) ResponseSigningFields { fields.ResultCode = "denied" return fields }, }, { name: "payload hash", mutate: func(fields ResponseSigningFields) ResponseSigningFields { fields.PayloadHash = mustSHA256([]byte("other")) return fields }, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() mutated := BuildResponseSigningInput(tt.mutate(base)) assert.False(t, bytes.Equal(baseInput, mutated)) }) } } func TestParseEd25519ResponseSignerPEMRejectsMalformedPEM(t *testing.T) { t.Parallel() _, err := ParseEd25519ResponseSignerPEM([]byte("not-pem")) require.ErrorIs(t, err, ErrInvalidResponsePrivateKeyPEM) } func TestParseEd25519ResponseSignerPEMRejectsNonPKCS8PEM(t *testing.T) { t.Parallel() _, privateKey, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) pemBytes, err := x509.MarshalPKCS8PrivateKey(privateKey) require.NoError(t, err) block := pem.Block{ Type: "ED25519 PRIVATE KEY", Bytes: pemBytes, } _, err = ParseEd25519ResponseSignerPEM(pem.EncodeToMemory(&block)) require.ErrorIs(t, err, ErrInvalidResponsePrivateKeyPEM) } func TestParseEd25519ResponseSignerPEMRejectsNonEd25519Key(t *testing.T) { t.Parallel() privateKey, err := rsa.GenerateKey(rand.Reader, 1024) require.NoError(t, err) pemBytes, err := x509.MarshalPKCS8PrivateKey(privateKey) require.NoError(t, err) _, err = ParseEd25519ResponseSignerPEM(pem.EncodeToMemory(&pem.Block{ Type: "PRIVATE KEY", Bytes: pemBytes, })) require.ErrorIs(t, err, ErrInvalidResponsePrivateKey) } func TestSignAndVerifyResponseSignature(t *testing.T) { t.Parallel() _, privateKey, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) signer, err := NewEd25519ResponseSigner(privateKey) require.NoError(t, err) fields := ResponseSigningFields{ ProtocolVersion: "v1", RequestID: "request-123", TimestampMS: 123456789, ResultCode: "ok", PayloadHash: mustSHA256([]byte("payload")), } signature, err := signer.SignResponse(fields) require.NoError(t, err) require.NoError(t, VerifyResponseSignature(signer.PublicKey(), signature, fields)) fields.ResultCode = "changed" require.ErrorIs(t, VerifyResponseSignature(signer.PublicKey(), signature, fields), ErrInvalidResponseSignature) }