- Aus dem Ziel heraus, die Plastikkarten der Seattle Public Library und des King County Library System zu reduzieren, ging es darum, die JSON-, Bild- und Signaturstruktur von iPhone-Wallet-Pässen direkt zu bearbeiten
- Wallet unterstützt nur QR Code, PDF417, Aztec Code und Code 128, daher ließ sich der Codabar der Bibliothekskarte nicht als nativer Barcode einfügen; der tatsächlich scannbare Barcode wurde per Bild umgangen
- Pässe müssen mit einem von Apple vertrauten Schlüssel signiert werden; statt einer Apple-Developer-Mitgliedschaft für 99 US-Dollar pro Jahr wurden Zertifikat und Schlüssel aus einer iOS-Pass-App verwendet, die offline erstellen kann
- Durch die Kombination aus
storeCard-Layout, Logos in verschiedenen Auflösungen, Codabar-strip.pngund einem leerenPKBarcodeFormatCode128-Eintrag wird auf dem Bildschirm ein Bild-Barcode angezeigt, während das iOS-Verhalten zur Erhöhung der Bildschirmhelligkeit erhalten bleibt - Der fertige
.pkpassließ sich durch Manifest-Erzeugung, Signatur mitopenssl smimeund ZIP-Paketierung erstellen; vor dem Praxistest in der Bibliothek konnte ein separater Scanner den Barcode auf dem Smartphone-Bildschirm lesen
Ziel: Bibliotheks-Barcodes ohne Plastikkarte nutzen
- Die Seattle Public Library und das King County Library System geben Plastikkarten mit aufgedrucktem Barcode aus, die mit Ausleihkonten verknüpft sind
- Stand 2023 sind die meisten Funktionen der Bibliotheken in Seattle Self-Service, und normalerweise kann man den Bibliotheks-Barcode manuell eingeben
- Trotzdem ist es deutlich bequemer, den Barcode direkt anzuzeigen; das Ziel war daher, die kaum genutzte Plastikkarte nicht im Portemonnaie zu tragen, sondern in die iPhone-Wallet-App zu legen
Wallet-Pässe bestehen aus JSON, Bildern und Signaturen
- Die Wallet-App verwaltet heute Zahlungskarten, Ausweise, Schlüssel und mehr, aber beim Start von Passbook im Jahr 2012 verwaltete sie nur „Pässe“
- Laut Apples Pass-Dokumentation ist ein Pass eine eigenständige ZIP-Datei, die per E-Mail oder Web verteilt werden kann und JSON sowie PNGs enthält
- Der Kernaufbau einer
.pkpass-Datei ist einfachpass.json: beschreibt die Inhalte des Passes, die keine Bilder sindmanifest.json: Liste der SHA-1-Prüfsummen der anderen Dateiensignature: S/MIME-Signatur über den Inhalt vonmanifest.json- unterstützte Bilddateien
Fehlende Codabar-Unterstützung als erste Hürde
- Wallet-Pässe unterstützen nur vier Barcode-Typen
- QR Code
- PDF417
- Aztec Code
- Code 128
- Bibliothekskarten verwendeten das in Bibliotheken weit verbreitete Codabar-Format
- Es ist zwar möglich, dass Bibliotheks-Barcode-Scanner auch andere lineare Barcodes unterstützen, aber das einzige Format, von dem man sicher annehmen kann, dass es an allen Standorten funktioniert, ist Codabar
- Also musste statt der nativen Barcode-Funktion von Wallet ein scannbares Codabar-Bild erzeugt und in den Pass eingefügt werden
Das Problem mit dem Pass-Signaturzertifikat
- Wallet-Pässe benötigen eine kryptografische Signatur und müssen mit einem Schlüssel signiert sein, dem eine der Apple-Zertifizierungsstellen vertraut
- Für Zwecke wie automatische Updates eines Passes durch den Anbieter, etwa Gate- oder Sitzplatzänderungen bei Flugtickets, ist eine Signatur einigermaßen nachvollziehbar
- Als Apple-Entwickler kann man relativ einfach einen Pass-Signaturschlüssel erhalten, aber für diese Aufgabe sollten keine 99 US-Dollar pro Jahr gezahlt werden
Warum vorhandene Pass-Erstellungs-Apps nicht passten
- Es gab mehrere Pass-Design-Apps von Leuten, die bereits Apple-Entwickler sind, aber sie boten nicht das erforderliche Maß an Kontrolle
-
Kontrolle über die Logogröße
- Apple erlaubt für das Logo oben links auf einem Pass eine Höhe von maximal 50 device-independent pixels
- Für das quadratische Logo rechts neben dem Text war eine Höhe von etwa 40 px am passendsten
- Entwickler müssen
logo.png,logo@2x.pngundlogo@3x.pngjeweils bereitstellen, aber Apps erlauben meist nur die Auswahl eines einzelnen Logos und bieten keine Kontrolle über die Skalierung
-
Verhalten der Bildschirmhelligkeit
- Öffnet man einen Pass mit einem regulär unterstützten Barcode, wird der Bildschirm für besseren Kontrast beim Scanner heller
- Um iOS dazu zu bringen, den Bildschirm heller zu machen, ohne einen tatsächlich nicht funktionierenden Barcode anzuzeigen, musste
pass.jsondirekt bearbeitet werden - Auch kostenlos herunterladbare Apps begrenzten teils die Anzahl der in Wallet speicherbaren Pässe und verlangten eine Zahlung
Signaturschlüssel in einer Offline-Erstellungs-App finden
- Es wurden mehrere Pass-Erstellungs-Apps mit kostenlosem Einstieg heruntergeladen und geprüft, ob sie auch offline Pässe erzeugen können
- Tests im Flugmodus und bei deaktiviertem WLAN ergaben, dass mindestens eine App Pässe offline erstellen konnte
- Der konkrete Name dieser App wird nicht genannt, um eine Sperrung des Schlüssels zu vermeiden
- Der Ablauf war einfacher als erwartet
- Da iOS-Apps auf einem Apple-silicon-Mac ausgeführt werden können, wurde die App auf den Mac geladen
- Im verpackten iOS-App-Bundle wurde nach einer auffälligen
.p12-Datei gesucht - Da PKCS#12-Dateien ein Importpasswort benötigen, wurde
stringsauf das Haupt-Binary ausgeführt, um eine Zeichenkette zu finden, die wie ein Passwort aussah
- Beim Prüfen der Zertifikatsinformationen mit
openssl pkcs12erschien als issuer die Apple Worldwide Developer Relations Certification Authority - Auch die Zertifikatskette wird benötigt; das Zwischenzertifikat könnte im App-Bundle liegen und lässt sich auch über die URL in den X.509-Erweiterungsfeldern herunterladen
Aufbau des Pass-Layouts
- Bei den Pass-Stilen muss man zwischen
boarding pass,coupon,event ticket,genericundstore cardwählen - Für ein großes horizontales Bild ist ein Layout nötig, das ein
strip-Bild unterstützt- Kandidaten waren
coupon,event ticketundstore card - Als Form, die einer physischen Bibliothekskarte am ähnlichsten ist, wurde store card gewählt
- Kandidaten waren
pass.jsonenthält die folgenden WertepassTypeIdentifierteamIdentifierformatVersionserialNumberorganizationNamelogoTextdescriptionstoreCardbackgroundColorforegroundColorsharingProhibited
passTypeIdentifierundteamIdentifiermüssen jeweils mit den FeldernUIDundOUim subject des Apple-Zertifikats übereinstimmen- Jeder Pass, der mit demselben
passTypeIdentifiererstellt wird, benötigt eine eindeutigeserialNumber - Bilder werden je nach Verwendungszweck vorbereitet
icon.pngist erforderlich, wird aber auf dem Pass selbst nicht angezeigtlogo.pngist das Logo, das oben links angezeigt wird- Es werden
logo.pngmit 40×40,logo@2x.pngmit 80×80 undlogo@3x.pngmit 120×120 erzeugt logo@3x.pngwird nachicon.pngkopiert- Der vorab erzeugte Barcode kommt in
strip.png
Codabar-Barcode-Bild erstellen
- iOS skaliert und beschneidet
strip.pngpassend zur Box auf dem Gerätebildschirm, daher musstestrip.pngnicht in drei Auflösungen erzeugt werden - Beide Bibliothekskarten verwenden A und D als Start- und Stoppsymbole
- Start- und Stoppsymbole lassen sich am einfachsten mit einem Barcode-Scanner überprüfen; ohne Scanner kann man sie mit der Codabar-Codierungstabelle auf Wikipedia visuell vergleichen
- Es gab nicht viele direkt nutzbare Codabar-Generatoren online, aber das Format selbst ist leicht zu implementieren
- Im Prototyp wurde mit der Barcoders-Bibliothek für Rust ein SVG erzeugt, das SVG angepasst und anschließend als PNG exportiert
- Das finale Layout wurde mit Blick auf Scanbarkeit und die verkleinerte Darstellung durch iOS festgelegt
- Die Höhe des Barcodes wird auf das Doppelte der Gesamtzahl der Symbole einschließlich Start- und Stoppsymbol gesetzt
- Eine 13-stellige Barcode-Nummer hat zum Beispiel 15 Symbole, also wird die Höhe auf 30 Einheiten gesetzt
- Vor dem Start und nach dem Ende werden jeweils 15 Einheiten quiet space gelassen
- Ober- und unterhalb des Barcodes werden jeweils 50 Einheiten Padding gelassen
- Jede Einheit wird auf 8 Pixel vergrößert, damit iOS das Bild stets verkleinert
- Bei einem Beispiel-Barcode mit 15 Symbolen ist das endgültige Bild 1040 Pixel hoch, der Barcode selbst 240 Pixel
- Es wurde ein 69-zeiliges Shell-Skript geschrieben, das mit dem obigen Layout ein Codabar-BMP erzeugt und es mit
sipsnach PNG konvertiert - Speichert man die Ausgabe des Skripts als
strip.png, ist das Barcode-Bild für den Pass vorbereitet
Barcode-Nummer anzeigen und Bildschirmhelligkeit umgehen
- Die Barcode-Nummer wird als
secondaryFieldsunter dem Barcode angezeigtkey:numberlabel:CARD NUMBERvalue: Kartennummer
- iOS erhöht die Bildschirmhelligkeit, wenn ein Pass mit Barcode ausgewählt wird, um Scannern zu helfen
- Nur durch den als Bild eingefügten Codabar erkennt iOS nicht, dass ein Barcode vorhanden ist
- Auf oberster Ebene von
pass.jsonwird ein leerer Barcode-Eintrag angegeben, um dieses Verhalten zu umgehenmessageist eine leere ZeichenketteformatistPKBarcodeFormatCode128messageEncodingistiso-8859-1
- So wurde unten im Pass kein Barcode angezeigt, während das iPhone dennoch den Bildschirm wie bei einem Pass mit Barcode heller machte
Signatur und Paketierung
- Nachdem alle Dateien vorbereitet sind, muss
manifest.jsonerzeugt werden manifest.jsonist ein Objekt, dessen Schlüssel Dateinamen und dessen Werte SHA-1-Prüfsummen sind- Mit einer Kombination aus
sha1sumundjqwird das Manifest für die PNG-Dateien undpass.jsonerzeugt - Die Manifest-Signatur erfolgt mit dem Befehl
openssl smime- Signer-Zertifikat
- privater Schlüssel
- Apple-WWDR-Zwischenzertifikat
- Eingabe
manifest.json - Ausgabe
signature
- Mit der Option
-attimevonopenssl smimekann der gewünschte Signaturzeitpunkt angegeben werden- Der Optionswert ist ein UNIX-Epoch-Wert
- Selbst wenn ein von Apple erhaltenes oder gefundenes Zertifikat abgelaufen ist, kann mit diesem Zeitpunkt signiert werden
- Abschließend werden die folgenden Dateien zu einem ZIP gebündelt und daraus
.pkpasserstellt- PNG-Bilder
pass.jsonmanifest.jsonsignature
Testergebnisse und offene Punkte
- macOS hat ein Vorschau-Tool für Pässe, mit dem sich prüfen lässt, ob ein Pass gültig ist und im Großen und Ganzen korrekt aussieht
- Ist er ungültig, lassen sich Fehler in
Console.appfinden - Das Vorschau-Tool ist nicht zu 100 % genau, bietet aber einen Button zum Senden an das iPhone über iCloud
- Der fertige Pass wurde in einer echten Bibliothek noch nicht getestet
- Ein separater Barcode-Scanner konnte den Barcode auf dem Smartphone-Bildschirm genauso lesen wie die echte Plastikkarte
- Allerdings funktionierte das gut, wenn die Bildschirmhelligkeit auf Maximum gestellt wurde
- Sie wurde heller eingestellt als die Helligkeit, die durch den leeren Barcode-Workaround erreicht wird
- Es ist erfreulich, dass sich die Pass-Spezifikation in 10 Jahren kaum verändert hat; enttäuschend ist aber, dass für das Signieren eines harmlosen Passes aus PNG und JSON eine Apple-Developer-Mitgliedschaft für 99 US-Dollar pro Jahr nötig ist
- Für manche Pass-Funktionen mag eine Signatur erforderlich sein, aber für das, was hier gemacht wurde, sollte keine Signatur nötig sein
- Wenn Apple Wallet um Codabar-Unterstützung ergänzt, könnten digitale Bibliothekskarten unterstützt werden, ohne prüfen zu müssen, ob alle Scanner im gesamten Bibliothekssystem Code 128 unterstützen
1 Kommentare
Meinungen auf Hacker News
Als Nächstes wäre es schön, wenn auch die ORCA-Karte behandelt würde. Seattle ist eines der Technologiezentren der USA, aber nicht nur die U-Bahn/der ÖPNV selbst ist eher schlecht, er ist auch technologisch hinter fast allen großen Städten zurück, deren Nahverkehr ich genutzt habe.
Jede beliebige Stadt in Europa, CDMX oder Denver ist Seattle weit voraus, und persönlich fand ich Denver wohl am besten.
Eine der Institutionen, die ORCA betreiben, hatte einmal einen Blogbeitrag veröffentlicht, in dem angekündigt wurde, NFC-Support in die Android-App aufzunehmen. Dieser Beitrag ist inzwischen verschwunden, und auch Jahre später gibt es die Funktion immer noch nicht.
Wenn man dieselbe Karte nutzt, werden auch Umstiege und Mehrtagespässe nahtlos verarbeitet, und der korrekte Tarif wird automatisch angewendet, etwa indem nach einer bestimmten Anzahl von Fahrten innerhalb eines Zeitraums nichts mehr berechnet wird.
Die Bürotür öffnet sich per NFC-Karte, deshalb habe ich nachgesehen, ob das unter iOS möglich ist. Soweit ich mich erinnere, kontrolliert Apple die NFC-Hardware stärker als das allgemeine PassKit, sodass es mit normalen Apps schwierig ist.
Dort hieß es, Tap-to-Pay komme 2023 zu ORCA; damit das wahr wird, bleiben also noch etwa zwei Monate.
Da Google geschrieben hat, dass ORCA bald in Google Wallet unterstützt wird, bin ich optimistisch.
Wenn ihr Android-Nutzer seid und es nicht mögt, dass Google Wallet im Gegensatz zu Apple Passbook nicht einfach beliebige Barcodes aufnehmen kann, gibt es auf F-Droid eine hervorragende App namens Loyalty Card Keychain: https://f-droid.org/en/packages/protect.card_locker/
Man kann die Nummer direkt eingeben oder einen vorhandenen Barcode scannen und ihn in einem von mehreren Barcode-Formaten speichern, darunter Codabar. Tippt man auf dem Hauptbildschirm der App auf einen Eintrag, zeigt sie den erzeugten Barcode an und erhöht auch die Bildschirmhelligkeit.
Vielleicht weil sie außer dem Anzeigen von Barcodes kaum etwas tut, öffnet sich die App auch sehr schnell. Sie hat nur eine Funktion, ist aber vielleicht meine Lieblings-App.
Heutzutage scheint Catima empfohlen zu werden; ich habe es kurz ausprobiert, und es wirkt ähnlich simpel und scheint auf derselben Codebasis zu beruhen.
Es ist zwar umständlich, erfüllt aber den Zweck, und die Datenschutzrichtlinie ist gut.
Ich verstehe nicht, warum es sinnvoll sein soll, dass Pässe kryptografisch signiert sein müssen, und zwar mit einem Schlüssel, den Apples Zertifizierungsstelle kennt. Für solche Updates gibt es bereits gut unterstütztes HTTPS.
Vielleicht will Apple, dass Pässe nicht nur beim Update, sondern auch offline auf dem Telefon verifiziert werden können, aber es wirkt trotzdem seltsam. Ein böswilliger Akteur könnte den Pass einfach komplett austauschen, statt ihn zu aktualisieren.
Ich sehe überhaupt nicht, wie die Verknüpfung mit einem Apple-Developer-Account beim Update-Problem helfen soll.
Als Grund für die Anforderung, dass es sich um eine von Apple genehmigte Stelle handeln muss, fällt mir höchstens der Verkauf gefälschter Tickets ein. Ob eine pkpass-Datei namens „Konzert-X-Ticket“ echt ist oder nicht, lässt sich mit oder ohne diese Anforderung nicht feststellen.
Vielleicht soll bei Betrugsmeldungen der betreffende Developer-Account gesperrt werden können, aber auch das wirkt nicht wie eine Lösung. Die Kosten für einen Developer-Account dürften weit niedriger sein als das Geld, das man durch Betrug verdienen kann, bevor man erwischt wird.
Ich schicke mir einfach ein Barcode-PNG mit meiner Bibliothekskartennummer per E-Mail und öffne es am Kiosk in Photos oder in der Gmail-App.
Ich habe mit der MakePass-App einen Pass mit meinem StarBucks-Mitgliedscode erstellt, und wenn ich in die Nähe eines Geschäfts komme, das ich häufig besuche, schlägt mir das Telefon den StarBucks-Pass automatisch auf dem Sperrbildschirm vor.
Bei Veranstaltungstickets funktioniert es genauso: Wenn man Ort und Zeitraum angibt, wird der Pass beim Eintreffen vor Ort automatisch vorgeschlagen, ohne dass man danach suchen muss. Nach Ende der Veranstaltung wird er nicht mehr vorgeschlagen und in den Bereich „Expired Passes“ verschoben, sodass der Hauptbildschirm nicht zugemüllt wird.
MakePass: https://pvieito.com
Es war ein guter Blogbeitrag, aber am Ende steht: „Ich habe diesen Pass noch nicht in einer echten Bibliothek getestet.“
Ich verstehe, dass es ein Spaßprojekt war, aber ich weiß nicht, warum man nicht die 10 Minuten investiert hat, die nötig gewesen wären, um die endgültige Lösung zu testen, bevor man das Ergebnis teilt.
Beim Erstellen von Barcodes bevorzuge ich persönlich einen Barcode-Generator in PostScript
https://bwipp.terryburton.co.uk/
Dieses Problem habe ich gelöst, indem ich ein Foto der Bibliothekskarte gemacht habe. Beim Ausleihen von Büchern öffnet man das Foto und hält es vor den Scanner
Ich speichere alle Ausweise im Fotoalbum des Handys
Wenn man unter Android etwas Ähnliches machen möchte, gibt es Catima auf Google Play und F-Droid. Es unterstützt verschiedene Barcode-Typen
https://catima.app/
Günstige laserbasierte 1D-Barcode-Scanner können Barcodes nicht vom Bildschirm lesen. Mit eInk könnte es vielleicht funktionieren
Die Mitgliedskarte des Supermarkts, in den ich oft gehe, basiert auf einem Barcode, was unpraktisch ist; zum Glück imitiert der Barcode-Leser eine Tastatur, sodass man den Code einfach über die Tastatur eingeben kann
Kamerabasierte Scanner interessiert es nicht, ob die Barcode-Beleuchtung Umgebungslicht, eine eigene LED oder ein hintergrundbeleuchteter Bildschirm ist; laserbasierte Systeme sind dagegen auf die Reflexion ihres eigenen Lichts angewiesen und funktionieren daher auf aktiv hintergrundbeleuchteten Bildschirmen überhaupt nicht
Ich frage mich, ob es auf eInk- oder passiven LCD-Displays funktioniert
Äußerlich sieht es wie ein einfacher 2D-Typ mit roter Linie aus, aber offenbar kommt es doch auf die Hardware an
Die KCLS-Kontonummer habe ich einfach auswendig gelernt. Zum Auswendiglernen sollten etwa 30 Sekunden reichen; das ist natürlich von Person zu Person verschieden, aber ich denke, diese Methode ist schneller
Danach kann man statt den Barcode zu scannen einfach die Kontonummer eingeben, und das dauert wahrscheinlich weniger lang, als das Handy herauszuholen und bereitzuhalten
Ob SPL genauso funktioniert, weiß ich nicht. Ich wohne nicht in Seattle, daher kann ich es nicht prüfen