# Signaturen

> Was BatteryPass in jeder Passversion signiert, wie Hash und Ed25519-Signatur entstehen und wie Sie sie mit den veröffentlichten Schlüsseln prüfen.

Jede veröffentlichte Passversion ist signiert. So kann jeder prüfen, dass die Daten von Ihrer
BatteryPass-Installation stammen und danach nicht verändert wurden. Für die Prüfung braucht es weder ein Konto
noch einen Aufruf bei BatteryPass: Das öffentliche JSON und die veröffentlichten Schlüssel genügen.

## Was signiert wird

Bei der Veröffentlichung signiert BatteryPass zwei Dokumente jeder Version mit dem aktiven Schlüssel, in derselben
Transaktion, die sie speichert:

| Dokument              | Enthält                                                               | Hash und Signatur                 | Wo Sie es lesen                                                                                                                                                                                                                                                                           |
| --------------------- | --------------------------------------------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Öffentliches Dokument | Die Projektion auf die Stufe `public`, mit Bezeichnungen              | `public_hash`, `public_signature` | `document` und `verification` des öffentlichen JSON ([`getPublicPassport`](https://passport.kabin.sh/docs/de/api-reference/public/get-public-passport)); `public_document` von [`getPassportVersion`](https://passport.kabin.sh/docs/de/api-reference/passports/get-passport-version) |
| Snapshot              | Jedes Feld in jeder Zugriffsstufe, mit Herkunft und Dokumentverweisen | `canonical_hash`, `signature`     | `snapshot` von [`getPassportVersion`](https://passport.kabin.sh/docs/de/api-reference/passports/get-passport-version), für Ihre Organisation                                                                                                                                            |

Das öffentliche Dokument sieht jeder Scanner, also kann es jeder prüfen. Der Snapshot belegt den vollständigen
Datensatz gegenüber Ihnen und gegenüber Behörden, denen Sie ihn vorlegen. Im öffentlichen JSON ist nur
`document` signiert; die Geschwister `passport_id`, `status`, `valid_until`, `verification` und `links` ändern
sich im Leben eines Passes und sind nicht abgedeckt.

```json title="verification"
{
  "algorithm": "Ed25519",
  "canonicalization": "RFC8785",
  "hash": "sha256:22471733ece6d811d244144731fc505180c5e7760a7a016c1322338bce0f56e5",
  "signature": "w0nnz3kjhrEGb1DtMoGp9qlH9g8q0h9YDJRb2jfabq7AOzPMUpnWXoxmIlptgJPTDVy3LWxLQkOpQYuGYXgJ4w",
  "key_id": "2027-10-k2",
  "signed_at": "2026-10-24T09:15:02Z",
  "keys_url": "https://batterypass.example.com/.well-known/batterypass/keys.json"
}
```

## Wie eine Signatur entsteht und geprüft wird

1. **Kanonisieren**

   Serialisieren Sie das signierte Objekt (`document` oder `snapshot`) mit dem JSON Canonicalization Scheme,
   JCS (RFC 8785). JCS sortiert die Objektfelder, entfernt Leerraum und schreibt Zahlen und Zeichenketten in
   einer festgelegten Form; dieselben Daten ergeben so immer dieselben Bytes. Kanonisieren Sie das geparste
   Objekt, nicht die Bytes der Antwort.

2. **Hashen**

   Berechnen Sie SHA-256 über die kanonischen Bytes und schreiben Sie ihn als `sha256:` gefolgt vom Hex-Digest
   in Kleinbuchstaben. Er muss `verification.hash` entsprechen (bzw. `public_hash`, `canonical_hash`).

3. **Schlüssel finden**

   Laden Sie das JWK-Set von `/.well-known/batterypass/keys.json` der BatteryPass-Adresse, der Sie vertrauen,
   und nehmen Sie den Schlüssel, dessen `kid` gleich `verification.key_id` ist. `keys_url` ist nicht signiert:
   zeigt es auf eine andere Adresse, gilt die Prüfung als fehlgeschlagen.

4. **Prüfen**

   Dekodieren Sie `x` des Schlüssels und die Signatur aus base64url ohne Padding (32 und 64 Bytes) und prüfen
   Sie die Ed25519-Signatur über die kanonischen Bytes, nicht über den Hash.

Die [Anleitung zur Signaturprüfung](https://passport.kabin.sh/docs/de/guides/verify-signature) zeigt das Schritt für Schritt mit
vollständigem Code.

## Die veröffentlichten Schlüssel

Die öffentlichen Schlüssel liegen als JWK-Set unter `/.well-known/batterypass/keys.json` Ihrer
BatteryPass-Adresse, außerhalb von `/api/v1`. Das Set braucht keinen Schlüssel, ist von jedem Ursprung aus
lesbar (CORS) und darf eine Stunde zwischengespeichert werden.

```json title="keys.json"
{
  "keys": [
    { "kty": "OKP", "crv": "Ed25519", "x": "WuoaQRoQuh2kPs5yYB6HxNz3Y58ndE8fRHnzG10NxoU", "kid": "2027-10-k2", "use": "sig", "alg": "EdDSA" },
    { "kty": "OKP", "crv": "Ed25519", "x": "JEpD6r2NnmNrL4_7UWS9wIWLFyjCfaSClypHm110Vl4", "kid": "2026-10-k1", "use": "sig", "alg": "EdDSA" }
  ]
}
```

Der aktive Schlüssel steht an erster Stelle. Schlüssel wechselt der Betreiber Ihrer Installation: Ein neuer
Schlüssel signiert neue Versionen, die alten öffentlichen Schlüssel bleiben im Set, damit frühere Signaturen
weiter prüfbar sind. Ein Schlüssel, der eine veröffentlichte Version signiert hat, wird nie entfernt.
Zwischenspeichern Sie Schlüssel nach `kid` und laden Sie das Set erneut, wenn Ihnen eine unbekannte `kid`
begegnet.

## Prüfung auf dem Server oder offline

|                  | [`verifyPassport`](https://passport.kabin.sh/docs/de/api-reference/public/verify-passport)          | Offline-Prüfung                                                                    |
| ---------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| Was geprüft wird | Beide Signaturen und beide Hashes einer Version gegen die gespeicherten Dokumente                     | Das öffentliche Dokument, das Ihnen vorliegt, gegen den veröffentlichten Schlüssel |
| Ergebnis         | `valid`, `public_document_valid`, `snapshot_valid`, `key_id`, `version_no`, `signed_at`, `checked_at` | Ihr eigenes Ja oder Nein                                                           |
| Vertrauen        | Sie vertrauen der Antwort des Servers                                                                 | Sie vertrauen nur dem Schlüssel, den Sie fest hinterlegen können                   |
| Braucht          | Die UUID des Passes; `version_no` optional (Standard: aktuelle Version)                               | Das öffentliche JSON und das JWK-Set                                               |

`verifyPassport` ist eine Abkürzung für eine schnelle Prüfung. Für einen unabhängigen Nachweis, etwa in einem
Archiv oder im System eines Kunden, prüfen Sie offline.

> [!NOTE]
> Eine gültige Signatur zeigt, dass diese BatteryPass-Installation genau diese Daten in dieser Version
> veröffentlicht hat. Sie sagt nichts darüber, ob die Daten richtig oder vollständig sind, und sie ist kein
> qualifiziertes elektronisches Siegel nach eIDAS.
