2 Punkte von GN⁺ 2023-10-29 | 1 Kommentare | Auf WhatsApp teilen
  • 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.png und einem leeren PKBarcodeFormatCode128-Eintrag wird auf dem Bildschirm ein Bild-Barcode angezeigt, während das iOS-Verhalten zur Erhöhung der Bildschirmhelligkeit erhalten bleibt
  • Der fertige .pkpass ließ sich durch Manifest-Erzeugung, Signatur mit openssl smime und 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 einfach
    • pass.json: beschreibt die Inhalte des Passes, die keine Bilder sind
    • manifest.json: Liste der SHA-1-Prüfsummen der anderen Dateien
    • signature: S/MIME-Signatur über den Inhalt von manifest.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.png und logo@3x.png jeweils 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.json direkt 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 strings auf das Haupt-Binary ausgeführt, um eine Zeichenkette zu finden, die wie ein Passwort aussah
  • Beim Prüfen der Zertifikatsinformationen mit openssl pkcs12 erschien 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, generic und store card wählen
  • Für ein großes horizontales Bild ist ein Layout nötig, das ein strip-Bild unterstützt
    • Kandidaten waren coupon, event ticket und store card
    • Als Form, die einer physischen Bibliothekskarte am ähnlichsten ist, wurde store card gewählt
  • pass.json enthält die folgenden Werte
    • passTypeIdentifier
    • teamIdentifier
    • formatVersion
    • serialNumber
    • organizationName
    • logoText
    • description
    • storeCard
    • backgroundColor
    • foregroundColor
    • sharingProhibited
  • passTypeIdentifier und teamIdentifier müssen jeweils mit den Feldern UID und OU im subject des Apple-Zertifikats übereinstimmen
  • Jeder Pass, der mit demselben passTypeIdentifier erstellt wird, benötigt eine eindeutige serialNumber
  • Bilder werden je nach Verwendungszweck vorbereitet
    • icon.png ist erforderlich, wird aber auf dem Pass selbst nicht angezeigt
    • logo.png ist das Logo, das oben links angezeigt wird
    • Es werden logo.png mit 40×40, logo@2x.png mit 80×80 und logo@3x.png mit 120×120 erzeugt
    • logo@3x.png wird nach icon.png kopiert
    • Der vorab erzeugte Barcode kommt in strip.png

Codabar-Barcode-Bild erstellen

  • iOS skaliert und beschneidet strip.png passend zur Box auf dem Gerätebildschirm, daher musste strip.png nicht 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 sips nach 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 secondaryFields unter dem Barcode angezeigt
    • key: number
    • label: CARD NUMBER
    • value: 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.json wird ein leerer Barcode-Eintrag angegeben, um dieses Verhalten zu umgehen
    • message ist eine leere Zeichenkette
    • format ist PKBarcodeFormatCode128
    • messageEncoding ist iso-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.json erzeugt werden
  • manifest.json ist ein Objekt, dessen Schlüssel Dateinamen und dessen Werte SHA-1-Prüfsummen sind
  • Mit einer Kombination aus sha1sum und jq wird das Manifest für die PNG-Dateien und pass.json erzeugt
  • 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 -attime von openssl smime kann 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 .pkpass erstellt
    • PNG-Bilder
    • pass.json
    • manifest.json
    • signature

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.app finden
  • 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

 
GN⁺ 2023-10-29
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.

    • Vor ein paar Tagen hieß es, Google Wallet werde das bald unterstützen: https://blog.google/products/google-pay/commute-around-the-w...
    • Unser lokales Verkehrssystem hat kürzlich Tap-to-Pay eingeführt, sodass man jede Kreditkarte sowie Apple Pay/Google Pay verwenden kann.
      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.
    • Ich frage mich, wie viel es kostet, ein System zur Fahrgelderhebung zu betreiben, verglichen damit, dass die meisten ÖPNV-Systeme nur einen Teil ihrer Einnahmen verlieren würden, wenn sie auf kostenlose Fahrten umstellen.
    • In dem Zusammenhang: Gibt es nicht eine Möglichkeit, mit einem gerooteten Android NFC-Karten zu klonen?
      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.
    • https://info.myorca.com/news/can-i-use-my-phone-to-pay-for-a...
      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.

    • Auf Apple erstellt man mit Pass4Wallet eine „Karte“ und importiert sie dann in Apple Wallet.
      Es ist zwar umständlich, erfüllt aber den Zweck, und die Datenschutzrichtlinie ist gut.
    • Es gibt auch eine App, mit der man beliebige Barcodes in Google Wallet einfügen kann: https://play.google.com/store/apps/details?id=color.dev.com....
  • 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.

    • Es würde ausreichen, wenn der ursprüngliche Pass den öffentlichen Schlüssel angibt, der Updates autorisieren darf.
      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.

    • Wallet-Pässe können einen Ort und Zeitraum definieren, in dem der jeweilige Pass als „relevant“ angezeigt wird.
      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
    • Beim Überfliegen des Artikels habe ich die ganze Zeit gesucht, warum er nicht einfach ein Foto gemacht hat.
  • 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.

    • Dieser Teil hat dem ganzen Beitrag die Wirkung genommen. Es fühlt sich an wie: „Ich habe eine großartige wissenschaftliche Theorie über Sauerstoffverlust beim Laufen. Zugegeben, ich habe noch nicht mit dem Joggen angefangen, aber …“
    • Am Ende ist es nur ein Haufen Pixel, der einen Barcode darstellt, der gescannt werden soll. Wenn er korrekt angezeigt wird, was kann da schon schiefgehen?
    • Vielleicht hat die Bibliothek samstags nicht geöffnet.
  • 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 habe das Barcode-Bild in eine ortsbasierte Benachrichtigung gelegt; wenn ich in die Stadtteilbibliothek gehe, erscheint es als Benachrichtigung
    • Bei einem statischen Barcode reicht ein Foto völlig aus. Der Vorteil, ihn in Wallet zu speichern, ist nicht besonders groß
      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/

    • Man kann auch Google Pay oder Samsung Pay verwenden
  • 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

    • Nach meinem Verständnis liegt das daran, dass ältere Systeme nicht mit einem digitalen Bildsensor scannen, sondern mit einem rotierenden Laserstrahl und einer einfachen Fotodiode die Helligkeitsänderungen lesen, die von den weißen/schwarzen Bereichen des Barcodes reflektiert werden
      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
    • Ich habe mit einem Bluetooth-MCU und einem E-Ink-Display eine günstige Barcode-Anzeige gebaut, und mit reinen 1D-Barcode-Scannern funktioniert sie überall gut
    • Ich bin jedes Mal beeindruckt, wie schnell und einfach die tragbaren Scanner von Costco den Mitgliedsbarcode lesen, der sehr schmal und klein auf die Mitgliedskarte gedruckt ist
      Ä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

    • Wenn man sie nicht auswendig lernen möchte, kann man sie im Passwortmanager seiner Wahl speichern