package signer import ( "context" "crypto/ed25519" "crypto/rand" "encoding/base64" "errors" "testing" "basicstack.de/proofedmesh/services/signing-service/internal/canonical" ) func newKey(t *testing.T) ed25519.PrivateKey { t.Helper() _, priv, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatal(err) } return priv } func TestInMemory_SignRoundtrip(t *testing.T) { priv := newKey(t) m := NewInMemory() m.AddKey("test-key", priv) stmt := Statement{ "_type": "https://in-toto.io/Statement/v1", "predicateType": "https://basicstack.de/attestations/rate_change/v1", "subject": []any{map[string]any{"name": "per_diem_rate/PDR-1", "digest": map[string]any{"sha256": "deadbeef"}}}, "predicate": map[string]any{"change_kind": "create"}, } s, err := SignStatement(context.Background(), m, "test-key", stmt) if err != nil { t.Fatalf("sign: %v", err) } if s.Envelope.PayloadType != "application/vnd.in-toto+json" { t.Errorf("payload type: %q", s.Envelope.PayloadType) } if len(s.Envelope.Signatures) != 1 { t.Fatalf("signatures: %d", len(s.Envelope.Signatures)) } if s.Envelope.Signatures[0].KeyID != "test-key" { t.Errorf("keyid: %q", s.Envelope.Signatures[0].KeyID) } // Verify the signature verifies against the public key. pub := priv.Public().(ed25519.PublicKey) payloadBytes, err := base64.RawURLEncoding.DecodeString(s.Envelope.Payload) if err != nil { t.Fatalf("decode payload: %v", err) } pae := encodePAE("application/vnd.in-toto+json", payloadBytes) sig, err := base64.RawURLEncoding.DecodeString(s.Envelope.Signatures[0].Sig) if err != nil { t.Fatalf("decode sig: %v", err) } if !ed25519.Verify(pub, pae, sig) { t.Fatal("signature does not verify against public key") } // content_hash should be reproducible from the envelope. envBytes, _ := canonical.Marshal(s.Envelope) expected := "sha256:" + canonical.SHA256Hex(envBytes) if s.ContentHash != expected { t.Errorf("content_hash mismatch:\n got: %s\nwant: %s", s.ContentHash, expected) } } func TestInMemory_UnknownKeyRef(t *testing.T) { m := NewInMemory() _, _, err := m.Sign(context.Background(), "nope", []byte("x")) if !errors.Is(err, ErrUnknownKey) { t.Fatalf("expected ErrUnknownKey, got %v", err) } } func TestOpenBao_StubReturnsNotWired(t *testing.T) { _, _, err := OpenBao{}.Sign(context.Background(), "k", []byte("x")) if !errors.Is(err, ErrNotWired) { t.Fatalf("expected ErrNotWired, got %v", err) } } func TestEncodePAE_FormatIsExact(t *testing.T) { got := encodePAE("application/vnd.in-toto+json", []byte("hello")) // "application/vnd.in-toto+json" is 28 bytes, "hello" is 5 bytes. want := []byte("DSSEv1 28 application/vnd.in-toto+json 5 hello") if string(got) != string(want) { t.Errorf("PAE mismatch:\n got: %q\nwant: %q", got, want) } } func TestDecodeHexEd25519Key_RejectsWrongLength(t *testing.T) { if _, err := DecodeHexEd25519Key("deadbeef"); err == nil { t.Fatal("expected error for short key") } }