/// Litzki Systems LLC — Produktspezifikation (Entwurf)

SovereignAttestation — Format & Prüfverfahren

Zur Verbindlichkeit dieser Übersetzung. Maßgeblich ist die englische Fassung. Sie ist das Ziel von @context und spec_url in jedem ausgestellten Dokument und damit die normative Quelle; diese Seite ist eine Übersetzung zur Erleichterung der Prüfung. Bei Abweichungen gilt die englische Fassung. Die normativen Schlüsselwörter MUST, MUST NOT und SHOULD sind bewusst unübersetzt: sie haben die in RFC 2119 festgelegte Bedeutung, und eine deutsche Entsprechung würde eine zweite normative Begriffswelt schaffen. Feldnamen, Urteilswerte und URLs bleiben ebenfalls unverändert — sie sind Kennungen, keine Begriffe.

1. Was dies ist (und was nicht)

Für eine Domain, die eine SOVP-Validierung durchlaufen hat, existieren zwei Dokumente:

DokumentOrtSigniert mitAussage
sovp-identity.json /.well-known/ der geprüften Domain selbst eigener Schlüssel der geprüften Domain (_sovp.<subject-domain>, ggf. treuhänderisch verwaltet) „Ich bin diese Domain“ — selbstbehauptete Identität
sovp-attestation.json /.well-known/ der geprüften Domain selbst Ausstellerschlüssel der Litzki Systems LLC (_sovp-attestation.litzki-systems.com) „Litzki bescheinigt dieses Urteil über diese Domain“ — Attestierung durch Dritte

Das sind zwei voneinander unabhängige Vertrauensaussagen von unabhängigen Signierern, die gegen unabhängig in DNS verankerte Schlüssel geprüft werden. Wer sich auf das Urteil verlässt, vertraut der Attestierung, die der Aussteller signiert hat. Der scan-Block im Identitätsdokument liegt, falls vorhanden, für Vertrauensentscheidungen ausdrücklich außerhalb des Geltungsbereichs (draft-litzki-sovp-04 §5) — er ist kein Ersatz für diese Attestierung und darf nicht als solcher gelesen werden.

Warum dies ein eigenes Dokument ist. draft-litzki-sovp-04 §8.3 (Layer Boundaries) formuliert genau die Anforderung, zu deren Erfüllung dieser Dokumenttyp existiert: Bewertungsergebnisse wie Urteile oder Scores erfordern ein eigenes signiertes Dokument, ausgestellt unter einem Schlüssel, den der Prüfer unabhängig auflöst (für diesen Schlüssel verweist der Draft auf seinen eigenen §8.2), und das Format eines solchen Dokuments nimmt der Draft ausdrücklich aus seinem Geltungsbereich heraus. Diese Seite ist dieses Format. §8.2 (Anchor Authorization) bindet den Schlüssel: der Autorisierungspfad muss außerhalb des SOVP-Dokuments liegen und darf nicht von einer Kennung abgeleitet sein, die die attestierte Partei kontrolliert — Kontrolle über einen Schlüssel ist keine Autorisierung dieses Schlüssels. Deshalb liegt der Ausstellerschlüssel unter _sovp-attestation.litzki-systems.com, einem Label in der Zone des Ausstellers, und niemals unter dem _sovp-Label der geprüften Domain. Die Zwei-Dokumente-Trennung auf dieser Seite ist damit keine Produktentscheidung oberhalb des Drafts, sondern das, was der Draft von jedem verlangt, der ein signiertes Urteil veröffentlichen will.

Hinweis zur Selbstausstellung. Bei einer Kundendomain sind Aussteller und geprüfte Partei verschieden, und die Attestierung ist eine Aussage eines Dritten. Für litzki-systems.com sind beide dieselbe Partei: die unter /.well-known/sovp-attestation.json auf dieser Domain veröffentlichte Attestierung stellt die Litzki Systems LLC über ihre eigene Domain aus, und der sovereignScore von 100 ist selbst berichtet. Sie existiert, um das Dokumentformat und das Prüfverfahren aus Abschnitt 5 an einem echten Dokument vorzuführen. Sie ist keine Zusicherung eines Dritten über diese Website.

draft-litzki-sovp-04 §8.2 erlaubt diese Konstellation ausdrücklich — Aussteller und geprüfte Partei dürfen dieselbe Organisation sein —, weil die Autorisierungsbedingung am Schlüsselpfad hängt und nicht an den Parteien: der Schlüssel muss aus einem Label aufgelöst werden, das die geprüfte Partei nicht kontrolliert, und das gilt hier, obwohl beide Rollen bei der Litzki Systems LLC liegen. Erlaubt ist aber nicht gleichbedeutend mit unabhängig. Wer Unabhängigkeit braucht, braucht einen anderen Aussteller, nicht eine andere Lesart dieses Dokuments.

2. Dokumentstruktur

{
  "@context": "https://litzki-systems.com/protocol/sovp-attestation-v1",
  "@type": "SovereignAttestation",
  "subject": {
    "domain": "example.com",
    "canonical_url": "https://example.com"
  },
  "attestation": {
    "verdict": "CERTIFIED",
    "sovereignScore": 87.4,
    "contentQuality": 91,
    "aiReadiness": 88,
    "infrastructureScore": 79,
    "authorityScore": 62,
    "anchorScore": 70,
    "vault_payload_digest": "<sha256 hex, optional>",
    "scanned_at": "2026-07-22T10:00:00.000Z",
    "valid_until": "2026-10-20T10:00:00.000Z",
    "spec_url": "https://litzki-systems.com/protocol/sovp-attestation-v1"
  },
  "issuer": {
    "uid": "urn:sovp:litzki-systems-llc",
    "canonical_url": "https://litzki-systems.com"
  },
  "integrity_proof": {
    "signature": "<base64>",
    "created": "2026-07-22T10:00:03.000Z",
    "public_key_ref": "dns:txt:_sovp-attestation.litzki-systems.com",
    "nonce": "<uuid4>"
  }
}

@context und spec_url zeigen auf die englische Fassung dieser Spezifikation, nicht auf diese Übersetzung. Beide sind Kennungen innerhalb des signierten Bereichs: eine sprachabhängige URL würde zwei Formate suggerieren, wo es eines gibt, und die kanonischen Bytes verändern. Ein Dokument, dessen @context auf /de/protocol/… zeigt, wurde nicht nach dieser Spezifikation ausgestellt.

spec_url verweist auf diese Spezifikation und nicht auf den IETF-Identitätsdraft — die Attestierung ist ein Produktartefakt von Litzki, und ein Verweis auf den Draft würde sie als IETF-spezifiziertes Objekt ausgeben.

attestation.vault_payload_digest ist optional: ein SHA-256-Digest (hex) des JCS-kanonisierten Sovereign-Vault-Datensatzes, für den diese Attestierung ausgestellt wurde. Weil das Feld im signierten Bereich liegt, bindet es Bewertungsschwelle und Scores des Vault-Datensatzes an diese Signatur — der Datensatz lässt sich nach der Ausstellung nicht mehr ändern, ohne die Attestierung zu entwerten. Attestierungen aus der Zeit vor Einführung des Feldes, und Prüfer, die es nicht auswerten, bleiben gültig.

Das Beispiel oben enthält kein parameterCount. Das Feld wurde am 2026-10-09 aus dieser Spezifikation entfernt: es war optional, hatte keinen definierten Wertebereich, keine Attestierung hat es jemals getragen, und die Anzahl der Parameter ist eine Eigenschaft der Scan-Engine zum Scan-Zeitpunkt, nicht dieses Dokumentformats. Ein Prüfer kanonisiert und verifiziert die jeweils vorhandenen Felder, deshalb verifiziert ein älteres Dokument mit diesem Feld weiterhin.

Zeitstempelformat. Zeitstempel in diesem Dokumenttyp sind RFC 3339, UTC, mit literalem Z-Suffix, und sie dürfen Sekundenbruchteile tragen: der Signierer gibt Millisekundenauflösung aus, im echten Dokument steht "scanned_at": "2026-09-08T23:17:55.646Z". draft-litzki-sovp-04 §5 verlangt für Zeitstempel im Identitätsdokument keine Sekundenbruchteile — diese Regel bindet das SovereignIdentity-Format, und dies ist ein bewusst eigener Dokumenttyp, die Abweichung ist also zulässig und kein Mangel. Sie hat eine Konsequenz, die ein Prüfer beachten muss: scanned_at und valid_until sind signierte Zeichenketten. Wer sie neu serialisiert — die Millisekunden weglässt, Z als +00:00 schreibt —, verändert die kanonischen Bytes und zerstört die Signatur. Für den Ablaufvergleich aus Abschnitt 7 werden sie als Zeitpunkte geparst, die Signatur wird aber über die Bytes geprüft, wie sie empfangen wurden. Das Beispiel oben verwendet die dreistellige Form, die der Signierer tatsächlich ausgibt.

attestation.anchorScore trägt den Namen, den die Engine seit 2026-08-05 verwendet. Dokumente, die vor diesem Datum ausgestellt wurden, tragen denselben Wert unter dem früheren Namen coherenceScore, falls solche existieren. Ein Prüfer kanonisiert und verifiziert die jeweils vorhandenen Felder, deshalb verifizieren beide Formen.

2.1 Wertemenge von attestation.verdict und Ausstellung

verdict ist einer der Werte "CERTIFIED", "NOT_CONFORMANT", "INCOMPLETE". Das Verdict-Modul der Engine definiert die Wertemenge in VERDICT, das Scoring-Modul gibt sie aus. VALID_VERDICTS im Verdict-Modul enthält zusätzlich FAILED, ausschließlich für Lesevorgänge.

"FAILED" ist ein Altwert. Die Engine hat ihn am 2026-09-03 in NOT_CONFORMANT umbenannt und schreibt ihn nirgends mehr. Lesbar bleibt er: ein gespeichertes FAILED wird beim Lesen auf NOT_CONFORMANT abgebildet, damit bestehende Datenbankzeilen, Vault-Datensätze und archivierte Dokumente gültig bleiben. Signierte Dokumente werden nie umgeschrieben; ein signiertes FAILED bleibt innerhalb seiner Signatur FAILED. Ein Prüfer, der gegen die ursprüngliche Wertemenge CERTIFIED/FAILED gebaut wurde, MUST einen unbekannten Wert als „nicht zertifiziert“ behandeln, niemals als „standardmäßig zertifiziert“.

INCOMPLETE bedeutet, dass der Scan nicht genug von der geprüften Domain erreichen konnte, um eine Messung zu erzeugen, etwa weil eine Firewall oder ein Bot-Schutz ihn blockiert hat. Es ist eine Aussage über die Messung, nicht über die Domain. NOT_CONFORMANT stellt fest, dass die Domain die SOVP-Identitätsartefakte nicht veröffentlicht hat. Eine nie gescannte Domain hat überhaupt kein Dokument.

Wie eine Attestierung ausgestellt wird. Die Ausstellung ist ein manueller Schritt auf dem Server. Ein Operator führt den eigenständigen Signierer gegen eine Eingabedatei aus und legt das Ergebnis unter /.well-known/sovp-attestation.json der geprüften Domain ab. Der Signierer ist ein eigenständiges Skript. Er ist nicht über HTTP erreichbar, nicht Teil eines Request-Handlers, und keine Route der Engine stellt eine Attestierung aus. Die Scan-Route signiert das separate SovereignIdentity-Dokument und schreibt niemals eine Attestierung. Welches Urteil eine Attestierung erhält, ist deshalb eine Operator-Entscheidung zum Ausstellungszeitpunkt, durchgesetzt vom Operator, nicht vom Code.

Der Ausstellerschlüssel ist von jedem Identitätsschlüssel getrennt. Er ist unter _sovp-attestation.litzki-systems.com veröffentlicht und unterscheidet sich von _sovp.litzki-systems.com. Beide Schlüssel liegen auf derselben Maschine: die Schlüsseldatei gehört root mit Modus 600 auf dem Server, der auch die Engine betreibt, und kein Request-Handler liest sie. Die Trennung ist eine von Schlüsselmaterial und DNS-Label, nicht eine von Maschinen.

Stand 2026-10-10: es wurde genau eine Attestierung ausgestellt, für litzki-systems.com, mit verdict: "CERTIFIED", gescannt am 2026-09-08 und gültig bis 2026-12-07. Es existiert keine Attestierung mit NOT_CONFORMANT oder INCOMPLETE. Attestierungen, die vor dem 2026-08-01 ausgestellt wurden, tragen ein Urteil aus der früheren Menge CERTIFIED/FAILED und werden nicht neu ausgestellt oder umklassifiziert: ein signiertes Dokument gibt das zum Scan-Zeitpunkt berechnete Urteil wieder.

3. Signierter Bereich

Die Ed25519-Signatur deckt jedes Feld der obersten Ebene außer integrity_proof ab — @context, @type, subject, attestation, issuer. Darin unterscheidet sich die Attestierung vom SovereignIdentity-Dokument, wo Hersteller-Erweiterungen wie scan außerhalb des signierten Bereichs liegen; hier sind Urteil und Scores der gesamte Zweck des Dokuments und liegen schon von der Konstruktion her innerhalb des signierten Bereichs.

integrity_proof.created und integrity_proof.nonce liegen außerhalb des signierten Bereichs und tragen keine kryptografische Zusicherung. Die signierten Zeitangaben sind attestation.scanned_at und attestation.valid_until. Beide unsignierten Felder lassen sich auf jeden beliebigen Wert umschreiben, ohne die Signatur zu entwerten, und das ist vorgeführt, nicht gefolgert: schreibt man am echten Dokument integrity_proof.created auf 2029-01-01T00:00:00.000Z und integrity_proof.nonce auf eine andere UUID um, meldet die Prüfung weiterhin Signature Verified Successfully; schreibt man das signierte attestation.scanned_at um, meldet sie Signature Verification Failure mit Exit-Code 1. Ein Prüfer MUST NOT created oder nonce als Aktualitätsmerkmal, als Replay-Schutz oder als Nachweis des Ausstellungszeitpunkts verwenden; die einzige Ablaufregel, die dieser Dokumenttyp definiert, ist der valid_until-Vergleich aus Abschnitt 7.

Es ist dieselbe strukturelle Schwäche, die draft-litzki-sovp-04 §9.4 (Replay Protection) für das Identitätsdokument schließt, indem er freshness.created und freshness.expiresAt innerhalb des signierten Bereichs verlangt — genau die Änderung, die Identitäts-Schema v2.0 von v1.4 unterscheidet, wo diese beiden Felder im unsignierten integrity_proof saßen, so wie sie es hier noch tun. Dieser Dokumenttyp hat diese Behandlung nicht erhalten. Die Lücke zu schließen heißt, beide Felder in ein signiertes freshness-Objekt zu verschieben; das ändert das Drahtformat und die kanonischen Bytes jedes Dokuments und erfordert deshalb einen neuen @context und eine Version 2 dieser Spezifikation, keine Textänderung auf dieser Seite. Bis dahin ist die Einschränkung oben die normative Aussage für Prüfer: created und nonce sind Anmerkungen des Ausstellers, kein Beweis.

4. Kanonisierung

Regel identisch zu draft-litzki-sovp-04 §4: die Nutzlast (alle signierten Felder) MUST vor dem Signieren oder Prüfen mit einer RFC-8785-konformen Implementierung des JSON Canonicalization Scheme (JCS) serialisiert werden. Nicht konforme Kanonisierer (improvisiertes JSON.stringify, handgeschriebene Sortierer, die nicht in Arrays absteigen, und Ähnliches) MUST NOT verwendet werden — sie zerstören die Prüfbarkeit zwischen Implementierungen stillschweigend, selbst wenn die Signaturmathematik im Übrigen korrekt ist. Die Referenzimplementierung nutzt das npm-Paket canonicalize (RFC-8785-konform); ein Prüfer in Python sollte aus demselben Grund das PyPI-Paket jcs verwenden.

5. Signaturalgorithmus

Ed25519 im Pure-Modus (RFC 8032 §5.1) direkt über JCS(payload) — vor dem Sign-/Verify-Aufruf wird kein externer Pre-Hash angewandt (Ed25519 wendet SHA-512 intern bereits an). Das ist mit Standardwerkzeugen direkt prüfbar, etwa:

openssl pkeyutl -verify -rawin \
  -pubin -inkey issuer_pubkey.pem \
  -sigfile signature.bin \
  -in canonical_payload.json

wobei canonical_payload.json die JCS-kanonisierten Nutzlast-Bytes enthält und signature.bin die base64-dekodierte integrity_proof.signature.

Die PEM-Dateien des Ausstellers aus den DNS-Einträgen erzeugen. Der TXT-Eintrag trägt den rohen 32-Byte-Ed25519-Schlüssel, openssl erwartet dagegen eine SubjectPublicKeyInfo-Struktur. Dem rohen Schlüssel wird das feste 12-Byte-Ed25519-SPKI-Präfix 302a300506032b6570032100 vorangestellt, dann wird konvertiert. Die Schlüssel werden in eine Liste gesammelt: das Label kann während eines Schlüsselwechsels bis zu vier v=SOVP1-Einträge tragen (Abschnitt 6), und es kann zusätzlich fremde TXT-Einträge tragen.

# Jeder veröffentlichte v=SOVP1-Schlüssel, einer pro Zeile. Niemals auf einen
# einzigen Wert zusammenziehen: `sed 's/.*k=//'` über eine Antwort mit mehreren
# Einträgen verkettet die Schlüssel und erzeugt eine zu große, unbrauchbare
# spki.bin.
dig +short TXT _sovp-attestation.litzki-systems.com \
  | sed 's/" "//g; s/^"//; s/"$//' \
  | grep '^v=SOVP1;' \
  | sed 's/.*k=//; s/[[:space:]]*$//'  > keys.txt

# Eine PEM-Datei pro veröffentlichtem Schlüssel.
n=0
while read -r KEY; do
  n=$((n + 1))
  printf '302a300506032b6570032100' | xxd -r -p  > spki.bin
  printf '%s' "$KEY" | base64 -d              >> spki.bin
  openssl pkey -pubin -inform DER -in spki.bin -out "issuer_pubkey-$n.pem"
done < keys.txt

Das Präfix ist für jeden Ed25519-Schlüssel konstant: 302a SEQUENCE über 42 Byte, 300506032b6570 AlgorithmIdentifier id-Ed25519 (OID 1.3.101.112), 032100 BIT STRING über 33 Byte mit 0 unbenutzten Bits. Nichts darin hängt vom Schlüssel ab.

Vollständiges Arbeitsbeispiel, am 2026-10-10 gegen das echte Dokument ausgeführt:

curl -s https://litzki-systems.com/.well-known/sovp-attestation.json -o att.json

python3 - <<'EOF'
import json, base64, jcs
d = json.load(open('att.json'))
payload = {k: v for k, v in d.items() if k != 'integrity_proof'}
open('canonical_payload.json', 'wb').write(jcs.canonicalize(payload))
open('signature.bin', 'wb').write(base64.b64decode(d['integrity_proof']['signature']))
EOF

ok=0; n=0
while read -r KEY; do
  n=$((n + 1))
  if openssl pkeyutl -verify -rawin -pubin -inkey "issuer_pubkey-$n.pem" \
       -sigfile signature.bin -in canonical_payload.json >/dev/null 2>&1; then
    ok=$n; break
  fi
done < keys.txt

[ "$ok" -gt 0 ] \
  && echo "Signature Verified Successfully (key $ok of $(wc -l < keys.txt))" \
  || echo "Signature Verification Failure: no published issuer key verifies this document"

Ergebnis: Signature Verified Successfully (key 1 of 1). keys.txt enthielt eine Zeile, der DNS-Eintrag löste zu v=SOVP1; k=fuBpokpFXyvjpsumM3Q0AZZYKMRilsbjhBZBhWEGfLo= auf (TTL 43200), die erzeugte PEM-Datei zu MCowBQYDK2VwAyEAfuBpokpFXyvjpsumM3Q0AZZYKMRilsbjhBZBhWEGfLo=, und die kanonische Nutzlast umfasste 551 Byte. Ändert man ein einzelnes Byte in canonical_payload.json, läuft das Ergebnis in den Fehlerzweig, openssl endet mit Exit-Code 1 — die Kontrolle, die belegt, dass die Prüfung wirklich greift.

Die Schleife ist das, was das Verfahren einen Schlüsselwechsel überleben lässt: sie probiert jeden veröffentlichten Schlüssel und ist erfolgreich, wenn einer von ihnen verifiziert — das Verhalten, das Abschnitt 6 verlangt. Auch gegen einen simulierten Schlüsselwechsel geprüft: liegt der passende Schlüssel an zweiter Stelle und ein fremder SPF-Eintrag in derselben Antwort, meldet die Schleife weiterhin Erfolg; ist nur ein nicht passender Schlüssel veröffentlicht, meldet sie den Fehlerzweig und kein falsch positives Ergebnis.

Das Verfahren verwendet dig, openssl, python3 und das Paket jcs. Die eine Abhängigkeit vorher installieren — sie ist nicht Teil der Python-Standardbibliothek:

python3 -m venv venv && ./venv/bin/pip install jcs
# den python3-Schritt oben danach als ./venv/bin/python ausführen

Es braucht keinen Code von Litzki Systems und keinen Zugang zu Litzki-Systems-Infrastruktur.

6. Schlüsselort (Vertrauensanker)

Der öffentliche Ed25519-Schlüssel des Ausstellers ist als DNS-TXT-Eintrag veröffentlicht:

_sovp-attestation.litzki-systems.com  IN TXT  "v=SOVP1; k=<base64-roher-32-Byte-Schlüssel>"

Format identisch zu draft-litzki-sovp-04 §7 (DNS TXT Record Format and Resolution). Dieses Label ist bewusst verschieden von _sovp.litzki-systems.com (dem SovereignIdentity-Schlüssel für litzki-systems.com selbst) und von jedem _sovp.<subject-domain>-Label (dem eigenen Identitätsschlüssel der geprüften Domain). Ein Prüfer löst den Ausstellerschlüssel unabhängig aus dem DNS auf. Nach draft-litzki-sovp-04 §9.7 (Public Key Source Authority) darf er den Schlüssel aus keiner anderen Quelle als diesem DNS-TXT-Eintrag beziehen — insbesondere nicht aus einem HTTP-Header-Feld und nicht aus einem Wert im Dokument selbst, denn ein Prüfer, der das täte, würde nur erfahren, dass das Dokument zu sich selbst passt. Er vertraut niemals einem im Dokument mitgelieferten Schlüssel und für diesen Zweck niemals einem Schlüssel unter dem _sovp-Label der geprüften Domain.

Es kann mehr als einen Schlüssel geben. §7 erlaubt einer Zone, mehrere v=SOVP1-Einträge gleichzeitig unter demselben Label zu veröffentlichen, um einen Schlüsselwechsel zu ermöglichen: ein Prüfer muss mindestens 4 Schlüssel berücksichtigen und darf mehr berücksichtigen, eine Zone sollte nicht mehr als 4 passende Einträge veröffentlichen, und die Schlüssel bilden eine unsortierte Menge — die Reihenfolge, in der ein Resolver die Einträge zurückgibt, hat keine Bedeutung. Ein Prüfer MUST deshalb jeden veröffentlichten Schlüssel durchprobieren und das Dokument annehmen, wenn einer von ihnen die Signatur verifiziert. Er MUST NOT beim ersten Eintrag stehen bleiben, MUST NOT annehmen, der erste Eintrag sei der aktuelle Schlüssel, und MUST Einträge ignorieren, deren Wert nicht mit v=SOVP1 beginnt — ein fremder TXT-Eintrag wie ein SPF-Eintrag kann sich die Antwort desselben Labels teilen. Der Sammelschritt in Abschnitt 5 ist für diesen Fall geschrieben: er erzeugt eine Liste, niemals einen Einzelwert. Stand 2026-10-10 ist unter diesem Label genau ein Schlüssel veröffentlicht.

Empfohlene TTL: betrieblich abhängig, kein fester Wert. Kurz (300 Sekunden, der in draft-litzki-sovp-04 §9.3, Key Revocation and DNS TTL, empfohlene Wert), solange der Ausstellerschlüssel häufig wechselt; länger (3600 Sekunden oder mehr), sobald er stabil ist — eine längere TTL senkt Resolver-Last und Auflösungszeit für Prüfer, ohne die Widerrufsgeschwindigkeit zu kosten, solange kein Wechsel ansteht. Vor einem geplanten Schlüsselwechsel die TTL wieder auf 300 Sekunden senken, damit der alte Schlüssel schnell aus den Caches fällt, sobald der neue veröffentlicht ist. Der Widerrufsmechanismus ist in beiden Fällen derselbe (TXT-Eintrag ändern oder entfernen).

7. Ablaufsemantik

attestation.valid_until ist entweder ein ISO-8601-Zeitstempel oder die literale Zeichenkette "permanent".

Die Prüfung liefert zwei unabhängige Ergebnisse, nicht einen zusammengefassten Wahrheitswert:

  • signature_valid (bool) — rein kryptografisch. Von Datumsangaben nie beeinflusst. Ein manipuliertes Dokument ist signature_valid: false, unabhängig davon, ob valid_until verstrichen ist.
  • status ("valid" | "expired") — rein der Vergleich von valid_until mit der aktuellen Zeit. Unabhängig von signature_valid.

Eine echte Attestierung nach Ablauf ihres valid_until ist {signature_valid: true, status: "expired"} — sie wurde nie gefälscht, sie ist verfallen. Verarbeitende Systeme MUST NOT eine abgelaufene, aber echte Attestierung als „ungültig“ oder „manipuliert“ melden; das sind verschiedene Fehlerfälle mit verschiedenen Konsequenzen (neuer Scan vs. Sicherheitsvorfall).

8. Prüfverfahren (informell)

  1. https://<subject-domain>/.well-known/sovp-attestation.json abrufen.
  2. Die TXT-Einträge von _sovp-attestation.litzki-systems.com auflösen. Jeden Eintrag behalten, dessen Wert mit v=SOVP1 beginnt, die übrigen verwerfen und aus jedem k=<base64> parsen. Während eines Schlüsselwechsels können es bis zu vier sein, in bedeutungsloser Reihenfolge (siehe §6). Für eine Prüfung auf der Kommandozeile jeden rohen Schlüssel wie in Abschnitt 5 nach PEM konvertieren.
  3. integrity_proof aus dem Dokument entfernen; den Rest JCS-kanonisieren.
  4. integrity_proof.signature per Ed25519 gegen die kanonischen Bytes prüfen und dabei jeden aus dem DNS aufgelösten öffentlichen Schlüssel nacheinander durchprobieren. Das Dokument ist signature_valid, wenn irgendein veröffentlichter Schlüssel es verifiziert; einen Fehler erst melden, nachdem alle Schlüssel probiert wurden.
  5. attestation.valid_until mit der aktuellen Zeit vergleichen.
  6. signature_valid und status getrennt ausgeben (siehe §7).

Zwei Dinge darf ein Prüfer in keinem Schritt tun: den Schlüssel aus dem Dokument statt aus dem DNS ableiten (§6) und integrity_proof.created oder integrity_proof.nonce als Aktualitäts- oder Replay-Schutz-Merkmal lesen — beide liegen außerhalb des signierten Bereichs (§3). Zeitstempel werden als Zeitpunkte verglichen, aber über die empfangenen Bytes geprüft, nie neu serialisiert (§2).

Referenzimplementierung: verify-attestation.mjs (Offline-Referenzprüfer, Node.js + canonicalize).

Änderungshistorie

Die Änderungshistorie bezieht sich auf die Spezifikation, nicht auf diese Übersetzung. Maßgeblich ist die englische Fassung.

  • 2026-10-10 — Abschnitt 3 stellt jetzt fest, dass integrity_proof.created und integrity_proof.nonce außerhalb des signierten Bereichs liegen und keine Zusicherung tragen, mit dem vorgeführten Kontrollpaar und dem Bezug zu draft-litzki-sovp-04 §9.4; das Schließen dieser Lücke ist auf eine Version 2 verschoben, weil es das Drahtformat ändert. Abschnitt 1 verankert die Zwei-Dokumente-Trennung in draft-litzki-sovp-04 §8.3 und die Trennung des Ausstellerschlüssels in §8.2, der auch den selbst ausgestellten Fall erlaubt. Abschnitt 6 dokumentiert, dass während eines Wechsels bis zu vier v=SOVP1-Einträge als unsortierte Menge veröffentlicht sein können und dass ein Prüfer jeden Schlüssel probieren muss; der Befehl zur Schlüsselextraktion in Abschnitt 5 wurde ersetzt, weil die vorherige dig | sed-Form mehrere Einträge zu einem unbrauchbaren Schlüssel verkettete, und das Arbeitsbeispiel iteriert jetzt über alle veröffentlichten Schlüssel. Abschnitt 2 dokumentiert das Zeitstempelformat samt der Sekundenbruchteile, die dieser Dokumenttyp trägt und das Identitätsdokument nicht, und die Beispiel-Zeitstempel wurden in sich konsistent gemacht. §9.7 als Quelle für die Schlüsselherkunftsregel ergänzt. Keine Änderung am Drahtformat: @context, spec_url und der signierte Bereich bleiben unverändert, und jedes bereits ausgestellte Dokument verifiziert weiterhin. Mit dieser Fassung erscheint die Spezifikation erstmals auf Deutsch.
  • 2026-10-09 — coherenceScore in anchorScore umbenannt, passend zur Engine seit 2026-08-05. Wertemenge des Urteils auf die drei Werte festgelegt, die die Engine ausgibt (CERTIFIED, NOT_CONFORMANT, INCOMPLETE), mit FAILED als lesbar bleibendem Altwert. Das optionale Feld parameterCount wurde entfernt: es hatte keinen definierten Wertebereich, und keine Attestierung hat es jemals getragen. Abschnitt 5 um die Schlüsselkonvertierung von DNS nach openssl und den Installationsschritt für die Abhängigkeit erweitert. Draft-Abschnittsnummern auf §7 (DNS-TXT-Format) und §9.3 (TTL-Empfehlung von 300 Sekunden) korrigiert; §4 und §5 waren bereits richtig. Drahtformat, @context und spec_url unverändert.
  • 2026-08-05 — optionales Feld attestation.vault_payload_digest ergänzt.
  • 2026-08-01 — Wertemenge des Urteils über das ursprüngliche Paar hinaus erweitert.
  • 2026-07-22 — Erstveröffentlichung.