diff --git a/filesig/json.go b/filesig/json.go
index 84906a0..7ec1c10 100644
--- a/filesig/json.go
+++ b/filesig/json.go
@@ -1,6 +1,7 @@
 package filesig
 
 import (
+	"encoding/base64"
 	"errors"
 	"fmt"
 
@@ -9,7 +10,9 @@ import (
 	"github.com/tidwall/sjson"
 	"golang.org/x/exp/slices"
 
+	"github.com/safing/jess"
 	"github.com/safing/jess/lhash"
+	"github.com/safing/structures/dsd"
 )
 
 // JSON file metadata keys.
@@ -32,10 +35,10 @@ func AddJSONChecksum(data []byte) ([]byte, error) {
 	checksums = append(checksums, h.Base58())
 
 	// Sort and deduplicate checksums and sigs.
-	slices.Sort[[]string, string](checksums)
-	checksums = slices.Compact[[]string, string](checksums)
-	slices.Sort[[]string, string](signatures)
-	signatures = slices.Compact[[]string, string](signatures)
+	slices.Sort(checksums)
+	checksums = slices.Compact(checksums)
+	slices.Sort(signatures)
+	signatures = slices.Compact(signatures)
 
 	// Add metadata and return.
 	return jsonAddMeta(content, checksums, signatures)
@@ -72,6 +75,86 @@ func VerifyJSONChecksum(data []byte) error {
 	return nil
 }
 
+func AddJSONSignature(data []byte, envelope *jess.Envelope, trustStore jess.TrustStore) (signedData []byte, err error) {
+	// Create session.
+	session, err := envelope.Correspondence(trustStore)
+	if err != nil {
+		return nil, fmt.Errorf("invalid signing envelope: %w", err)
+	}
+
+	// Check if the envelope is suitable for signing.
+	if err := envelope.Suite().Provides.CheckComplianceTo(fileSigRequirements); err != nil {
+		return nil, fmt.Errorf("envelope not suitable for signing: %w", err)
+	}
+
+	// Extract content and metadata from json.
+	content, checksums, signatures, err := jsonSplit(data)
+	if err != nil {
+		return nil, fmt.Errorf("invalid json structure: %w", err)
+	}
+
+	// Sign data.
+	letter, err := session.Close(content)
+	if err != nil {
+		return nil, fmt.Errorf("sign: %w", err)
+	}
+
+	// Serialize signature and add it.
+	letter.Data = nil
+	sig, err := letter.ToDSD(dsd.CBOR)
+	if err != nil {
+		return nil, fmt.Errorf("serialize sig: %w", err)
+	}
+	signatures = append(signatures, base64.RawURLEncoding.EncodeToString(sig))
+
+	// Sort and deduplicate checksums and sigs.
+	slices.Sort(checksums)
+	checksums = slices.Compact(checksums)
+	slices.Sort(signatures)
+	signatures = slices.Compact(signatures)
+
+	// Add metadata and return.
+	return jsonAddMeta(data, checksums, signatures)
+}
+
+func VerifyJSONSignature(data []byte, trustStore jess.TrustStore) (err error) {
+	// Extract content and metadata from json.
+	content, _, signatures, err := jsonSplit(data)
+	if err != nil {
+		return fmt.Errorf("invalid json structure: %w", err)
+	}
+
+	var signaturesVerified int
+	for i, sig := range signatures {
+		// Deserialize signature.
+		sigData, err := base64.RawURLEncoding.DecodeString(sig)
+		if err != nil {
+			return fmt.Errorf("signature %d malformed: %w", i+1, err)
+		}
+		letter := &jess.Letter{}
+		_, err = dsd.Load(sigData, letter)
+		if err != nil {
+			return fmt.Errorf("signature %d malformed: %w", i+1, err)
+		}
+
+		// Verify signature.
+		letter.Data = content
+		err = letter.Verify(fileSigRequirements, trustStore)
+		if err != nil {
+			return fmt.Errorf("signature %d invalid: %w", i+1, err)
+		}
+
+		signaturesVerified++
+	}
+
+	// Fail when no signatures were verified.
+	if signaturesVerified == 0 {
+		return ErrSignatureMissing
+	}
+
+	return nil
+}
+
 func jsonSplit(data []byte) (
 	content []byte,
 	checksums []string,
@@ -187,10 +270,9 @@ func jsonAddMeta(data []byte, checksums, signatures []string) ([]byte, error) {
 
 	// Final pretty print.
 	data = pretty.PrettyOptions(data, &pretty.Options{
-		Width:    200,  // Must not change!
-		Prefix:   "",   // Must not change!
-		Indent:   " ",  // Must not change!
-		SortKeys: true, // Must not change!
+		Width:  200, // Must not change!
+		Prefix: "",  // Must not change!
+		Indent: " ", // Must not change!
 	})
 
 	return data, nil
diff --git a/filesig/json_test.go b/filesig/json_test.go
index a1505f7..58d3e03 100644
--- a/filesig/json_test.go
+++ b/filesig/json_test.go
@@ -4,6 +4,10 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/safing/jess"
+	"github.com/safing/jess/tools"
 )
 
 func TestJSONChecksums(t *testing.T) {
@@ -22,9 +26,9 @@ func TestJSONChecksums(t *testing.T) {
 `
 
 	testJSONWithChecksum, err := AddJSONChecksum([]byte(json))
-	assert.NoError(t, err, "should be able to add checksum")
+	require.NoError(t, err, "should be able to add checksum")
 	assert.Equal(t, jsonWithChecksum, string(testJSONWithChecksum), "should match")
-	assert.NoError(t,
+	require.NoError(t,
 		VerifyJSONChecksum(testJSONWithChecksum),
 		"checksum should be correct",
 	)
@@ -33,7 +37,7 @@ func TestJSONChecksums(t *testing.T) {
 	"c": 1,     "a":"b",
 		"_jess-checksum": "ZwtAd75qvioh6uf1NAq64KRgTbqeehFVYmhLmrwu1s7xJo"
 	}`
-	assert.NoError(t,
+	require.NoError(t,
 		VerifyJSONChecksum([]byte(jsonWithChecksum)),
 		"checksum should be correct",
 	)
@@ -48,7 +52,7 @@ func TestJSONChecksums(t *testing.T) {
 		"c": 1
 	 }
 	 `
-	assert.NoError(t,
+	require.NoError(t,
 		VerifyJSONChecksum([]byte(jsonWithMultiChecksum)),
 		"checksum should be correct",
 	)
@@ -61,9 +65,9 @@ func TestJSONChecksums(t *testing.T) {
 `
 
 	testJSONWithMultiChecksum, err := AddJSONChecksum([]byte(jsonWithMultiChecksum))
-	assert.NoError(t, err, "should be able to add checksum")
+	require.NoError(t, err, "should be able to add checksum")
 	assert.Equal(t, jsonWithMultiChecksumOutput, string(testJSONWithMultiChecksum), "should match")
-	assert.NoError(t,
+	require.NoError(t,
 		VerifyJSONChecksum(testJSONWithMultiChecksum),
 		"checksum should be correct",
 	)
@@ -117,3 +121,106 @@ func TestJSONChecksums(t *testing.T) {
 	//
 	//	assert.Error(t, VerifyTextFileChecksum([]byte(textWithFailingChecksums), "#"), "should fail")
 }
+
+func TestJSONSignatures(t *testing.T) {
+	t.Parallel()
+
+	// Get tool for key generation.
+	tool, err := tools.Get("Ed25519")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Generate key pair.
+	s, err := getOrMakeSignet(t, tool.StaticLogic, false, "test-key-jsonsig-1")
+	if err != nil {
+		t.Fatal(err)
+	}
+	// sBackup, err := s.Backup(true)
+	// if err != nil {
+	// 	t.Fatal(err)
+	// }
+	// t.Logf("signet: %s", sBackup)
+
+	// Make envelope.
+	envelope := jess.NewUnconfiguredEnvelope()
+	envelope.SuiteID = jess.SuiteSignV1
+	envelope.Senders = []*jess.Signet{s}
+
+	// Test 1: Simple json.
+
+	json := `{"a": "b", "c": 1}`
+	testJSONWithSignature, err := AddJSONSignature([]byte(json), envelope, testTrustStore)
+	require.NoError(t, err, "should be able to add signature")
+	require.NoError(t,
+		VerifyJSONSignature(testJSONWithSignature, testTrustStore),
+		"signature should be valid",
+	)
+
+	// Test 2: Prepared json with signature.
+
+	// Load signing key into trust store.
+	signingKey2, err := jess.SenderFromTextFormat(
+		"sender:2ZxXzzL3mc3mLPizTUe49zi8Z3NMbDrmmqJ4V9mL4AxefZ1o8pM8wPMuK2uW12Mvd3EJL9wsKTn14BDuqH2AtucvHTAkjDdZZ5YA9Azmji5tLRXmypvSxEj2mxXU3MFXBVdpzPdwRcE4WauLo9ZfQWebznvnatVLwuxmeo17tU2pL7",
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	rcptKey2, err := signingKey2.AsRecipient()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := testTrustStore.StoreSignet(rcptKey2); err != nil {
+		t.Fatal(err)
+	}
+
+	// Verify data.
+	jsonWithSignature := `{
+			"c":1,"a":"b",
+			"_jess-signature": "Q6RnVmVyc2lvbgFnU3VpdGVJRGdzaWduX3YxZU5vbmNlRK6e7JhqU2lnbmF0dXJlc4GjZlNjaGVtZWdFZDI1NTE5YklEeBl0ZXN0LXN0YXRpYy1rZXktanNvbnNpZy0xZVZhbHVlWEBPEbeM4_CTl3OhNT2z74h38jIZG5R7BBLDFd6npJ3E-4JqM6TaSMa-2pPEBf3fDNuikR3ak45SekC6Z10uWiEB"
+		}`
+	require.NoError(t,
+		VerifyJSONSignature([]byte(jsonWithSignature), testTrustStore),
+		"signature should be valid",
+	)
+
+	// Test 3: Add signature to prepared json.
+
+	testJSONWithSignature, err = AddJSONSignature([]byte(jsonWithSignature), envelope, testTrustStore)
+	require.NoError(t, err, "should be able to add signature")
+	require.NoError(t,
+		VerifyJSONSignature(testJSONWithSignature, testTrustStore),
+		"signatures should be valid",
+	)
+
+	// Test 4: Prepared json with multiple signatures.
+
+	// Load signing key into trust store.
+	signingKey3, err := jess.SenderFromTextFormat(
+		"sender:2ZxXzzL3mc3mLPizTUe49zi8Z3NMbDrmmqJ4V9mL4AxefZ1o8pM8wPMuRAXdZNaPX3B96bhGCpww6TbXJ6WXLHoLwLV196cgdm1BurfTMdjUPa4PUj1KgHuM82b1p8ezQeryzj1CsjeM8KRQdh9YP87gwKpXNmLW5GmUyWG5KxzZ7W",
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	rcptKey3, err := signingKey3.AsRecipient()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := testTrustStore.StoreSignet(rcptKey3); err != nil {
+		t.Fatal(err)
+	}
+
+	jsonWithMultiSig := `{
+			"_jess-signature": [
+				"Q6RnVmVyc2lvbgFnU3VpdGVJRGdzaWduX3YxZU5vbmNlRK6e7JhqU2lnbmF0dXJlc4GjZlNjaGVtZWdFZDI1NTE5YklEeBl0ZXN0LXN0YXRpYy1rZXktanNvbnNpZy0xZVZhbHVlWEBPEbeM4_CTl3OhNT2z74h38jIZG5R7BBLDFd6npJ3E-4JqM6TaSMa-2pPEBf3fDNuikR3ak45SekC6Z10uWiEB",
+				"Q6RnVmVyc2lvbgFnU3VpdGVJRGdzaWduX3YxZU5vbmNlRC32oylqU2lnbmF0dXJlc4GjZlNjaGVtZWdFZDI1NTE5YklEeBl0ZXN0LXN0YXRpYy1rZXktanNvbnNpZy0yZVZhbHVlWEDYVHeKaJvzZPOkgC6Tie6x70bNm2jtmJmAwDFDcBL1ddK7pVSefyAPg47xMO7jeucP5bw754P6CdrR5gyANJkM"
+			],
+			"a": "b",
+			"c": 1
+		 }
+		 `
+	assert.NoError(t,
+		VerifyJSONSignature([]byte(jsonWithMultiSig), testTrustStore),
+		"signatures should be valid",
+	)
+}
diff --git a/filesig/main.go b/filesig/main.go
index 9934422..49c7027 100644
--- a/filesig/main.go
+++ b/filesig/main.go
@@ -53,7 +53,7 @@ func SignFileData(fileHash *lhash.LabeledHash, metaData map[string]string, envel
 
 	// Check if the envelope is suitable for signing.
 	if err := envelope.Suite().Provides.CheckComplianceTo(fileSigRequirements); err != nil {
-		return nil, nil, fmt.Errorf("envelope not suitable for signing")
+		return nil, nil, fmt.Errorf("envelope not suitable for signing: %w", err)
 	}
 
 	// Create struct and transform data into serializable format to be signed.
diff --git a/filesig/text_test.go b/filesig/text_test.go
index e896c75..9d69e56 100644
--- a/filesig/text_test.go
+++ b/filesig/text_test.go
@@ -4,6 +4,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 func TestTextChecksums(t *testing.T) {
@@ -29,20 +30,20 @@ do_something()
 `
 
 	testTextWithChecksumAfterComment, err := AddTextFileChecksum([]byte(text), "#", TextPlacementAfterComment)
-	assert.NoError(t, err, "should be able to add checksum")
+	require.NoError(t, err, "should be able to add checksum")
 	assert.Equal(t, textWithChecksumAfterComment, string(testTextWithChecksumAfterComment), "should match")
-	assert.NoError(t,
+	require.NoError(t,
 		VerifyTextFileChecksum(testTextWithChecksumAfterComment, "#"),
 		"checksum should be correct",
 	)
-	assert.NoError(t,
+	require.NoError(t,
 		VerifyTextFileChecksum(append(
 			[]byte("\n\n  \r\n"),
 			testTextWithChecksumAfterComment...,
 		), "#"),
 		"checksum should be correct",
 	)
-	assert.NoError(t,
+	require.NoError(t,
 		VerifyTextFileChecksum(append(
 			testTextWithChecksumAfterComment,
 			[]byte("\r\n \n \n")...,
@@ -62,9 +63,9 @@ do_something()
 `
 
 	testTextWithChecksumAtTop, err := AddTextFileChecksum([]byte(text), "#", TextPlacementTop)
-	assert.NoError(t, err, "should be able to add checksum")
+	require.NoError(t, err, "should be able to add checksum")
 	assert.Equal(t, textWithChecksumAtTop, string(testTextWithChecksumAtTop), "should match")
-	assert.NoError(t,
+	require.NoError(t,
 		VerifyTextFileChecksum(testTextWithChecksumAtTop, "#"),
 		"checksum should be correct",
 	)
@@ -82,9 +83,9 @@ do_something()
 `
 
 	testTextWithChecksumAtBottom, err := AddTextFileChecksum([]byte(text), "#", TextPlacementBottom)
-	assert.NoError(t, err, "should be able to add checksum")
+	require.NoError(t, err, "should be able to add checksum")
 	assert.Equal(t, textWithChecksumAtBottom, string(testTextWithChecksumAtBottom), "should match")
-	assert.NoError(t,
+	require.NoError(t,
 		VerifyTextFileChecksum(testTextWithChecksumAtBottom, "#"),
 		"checksum should be correct",
 	)
@@ -119,7 +120,7 @@ do_something()
 do_something()
 `
 	testTextWithMultiChecksumOutput, err := AddTextFileChecksum([]byte(textWithMultiChecksum), "#", TextPlacementAfterComment)
-	assert.NoError(t, err, "should be able to add checksum")
+	require.NoError(t, err, "should be able to add checksum")
 	assert.Equal(t, textWithMultiChecksumOutput, string(testTextWithMultiChecksumOutput), "should match")
 
 	// Test failing checksums.
@@ -135,7 +136,7 @@ do_something()
 
 do_something()
 `
-	assert.Error(t, VerifyTextFileChecksum([]byte(textWithFailingChecksums), "#"), "should fail")
+	require.Error(t, VerifyTextFileChecksum([]byte(textWithFailingChecksums), "#"), "should fail")
 }
 
 func TestLineEndDetection(t *testing.T) {