Blog

Systemkonkurrenz

Während die weise Staatsführung der Volksrepublik China nur nach reiflicher Überlegung sehr gezielt und kurzzeitig kleinere Einschränkungen der Bewegungsfreiheit ihrer Bürgerinnen vornimmt und Überlegungen zur Einführung totalitärer Maßnahmen europäischer Provenienz nach einem offenen, demokratischen Diskurs selbstkritisch und bedauernd zurückzieht, drohen im Nordkorea Europas ab Herbst wieder drastische Beschränkungen wie das Tragen einer Gesichtsmaske in der Umgebung alter und kranker Menschen.

Solidaridad

In Bezug auf die absehbar schwierige Energieversorgung im kommenden Winter geriert sich Deutschland als das Bayern Europas – wirtschaftlich stark und überaus selbstbewusst, aber mit einem eher unidirektionalen Verständnis von Solidarität ausgestattet. Man muss schon froh sein, dass Olaf Scholz die europäischen Partner nicht zum Fracking auffordert oder die Suche nach einem Endlager für deutschen Atommüll auf alle EU-Mitglieder mit Ausnahme Deutschlands ausweitet.

Leib- und Seelsorger

Angesichts der schwierigen Situation in der Kirchenprovinz Köln und weil traditionelle Formen des kirchlichen Widerstands gegen die Staatsgewalt nur noch selten auf ein größeres öffentliches Echo stoßen, hat ein Mitarbeiter des Bistums Aachen in Eigeninitiative versucht, eine Revitalisierung des brand claims Barmherzigkeit mit einer Stärkung der street credibility der Mater Ecclesia zu verbinden.

Eigeninitiative ist allerdings nicht nur der Kurie suspekt, und so wurden weder die gute Absicht noch die handwerkliche Leistung (in fünf manipulierten Dönern rund 153 Gramm Haschisch sowie mehrere Handys und Ladegeräte) von den Verantwortlichen des Bistums angemessen gewürdigt.

Expansion

Natürlich sollte die Auswahl von Software-Produkten sich nicht darauf beziehen, ob ein Software-Hersteller sympathischer ist als der andere, und bei einem guten Produkt nehme ich Risikokapital und Electron in Kauf, aber zum Glück ist Typinator auch ein sehr viel besseres Werkzeug als TextExpander.

Zahlungsunfähiger Datenroboter

Obwohl sich meine Backup-Strategie seit einigen Jahren nicht mehr auf Drobo-Produkte stützt, bedauere ich die finanziellen Schwierigkeiten des Unternehmens sehr.

Fahrerfreundlich

Die Tour de France wird ihrem Ruf als ausgesprochen fürsorgliche Sportveranstaltung auch in diesem Sommer gerecht:

Die anhaltend hohen Temperaturen haben auch Auswirkungen auf die Tour de France. Wegen der enormen Hitze ist das Extremwetter-Protokoll der Tour de France in Kraft getreten. Wie die Organisatoren mitteilten, gelten für die 15. Etappe von Rodez nach Carcassonne bei Temperaturen von 40 Grad drei Sonderregelungen. So dürfen sich die Fahrer vom Start weg bis zehn Kilometer vor dem Ziel verpflegen. Leere Flaschen dürfen auch außerhalb der Müllzonen weggeworfen werden, wenn Radsport-Fans am Straßenrand stehen. Zudem wurde die Karenzzeit - also der maximale Rückstand auf die Zeit des Siegers - auf 20 Prozent gesetzt, unabhängig von dessen Durchschnittsgeschwindigkeit.

Erdnüsse

Jorge Gonzáles bringt angesichts der drohenden Einschnitte bei der Finanzierung des DAAD ein beliebtes Argument gegen fast alle Kürzungen staatlicher Ausgaben sehr schön auf den Punkt:

Es geht hier um ein paar Millionen Euro im Jahr. Das ist nichts für einen Staatshaushalt!

Entsprechend kommen für eine Haushaltskonsolidierung eigentlich nur der gesamte Verteidigungshaushalt oder der Etat des Arbeitsministeriums in Frage.

Fernäsen

Webbrowser spielen eine herausgehobene Rolle auf den meisten Endgeräten, was das Ringen um die Monetarisierung ihrer Nutzung und die Privatsphäre der Nutzenden erklärt.

Die Idee, sämtliche Anwendungen in einer gemieteten Browser-Instanz auf einer virtuellen Maschine laufen zu lassen, ist einem konservativen Menschen wie mir allerdings nicht nur unter Nachhaltigkeitsaspekten sehr fremd.

Zero Trust 2

Apple hat heute einen so großen Schritt in die richtige Richtung unternommen, dass ich beinahe geneigt bin, dem Unternehmen die Vernachlässigung seiner Unix-Wurzeln nachzusehen. Warum aber der Lockdown Mode als extreme, optional protection for the very small number of users who face grave, targeted threats to their digital security beworben wird, ist mir schleierhaft.

AppleInsider versteigt sich sogar zu der Aussage

Everyone else should avoid using the feature for everyday situations, lest their devices become less useful for the sake of unnecessary security measures.

– obwohl technisch gestütztes Misstrauen gegenüber jeglichen Verbindungen zu fremden Menschen oder Geräten und vor allem gegenüber MDM-Profilen nicht nur dem Bund gut zu Gesicht steht.

Verschlüsselte Postkarte

AppleInsider stellt zwar noch einige verschlüsselte Messenger vor, hat aber eigentlich bereits resigniert:

And remember: if you wouldn't say or do something in public, it's wise not to send it across the internet, either. Even encrypted.

Нулевое доверие

Die größte Sorge des Auswärtigen Amtes in Bezug auf Cyberwar-Aktivitäten gilt nicht den Auswirkungen auf die kritische Infrastruktur in Deutschland oder der fehlenden Zurechenbarkeit von Angriffen, sondern der Bedrohung der vertrauensvollen Zusammenarbeit mit den russischen Strafverfolgungsbehörden durch Angriffe auf russische Systeme:

Wenn die selbst ernannten Online-Kämpfer einen deutschen Pass haben, ziehen die uns mit rein, verdeutlichte Grienberger. Da lasse sich dann nicht mehr unterscheiden, ob es sich um eine private oder staatliche Aktion handle. Wenn Russland auf uns zukommt und verlangt, die virtuellen Eindringlinge zu bestrafen, sind wir in einer schwierigen Situation. Es müsste daher dringend geklärt werden, wie kann man diese Leute wieder demobilisieren?

Man möchte sich gar nicht ausmalen, wie ungehalten die Russische Föderation auf eine verzögerte Auslieferung deutscher Hackerinnen reagieren würde.

Apfelhund

Einige Tage nach der konkreten Ankündigung von passkeys für die verschiedenen Apple-Betriebssysteme, ersten Katastrophenszenarien (die allerdings auch für MFA-Systeme einschlägig sind) und widersprüchlichen Heilsversprechen trägt Michael Tsai die naheliegenden Fragen vollständig zusammen:

I don’t understand the slide at the end where it says that Passkey protects against device theft but a password manager (maybe) doesn’t.

Other questions:

  • Can I get at my passkeys from Keychain Access?
  • Is there a way to manually back them up or move them between devices (other than manual AirDropping one at a time)? It would be nice to have a backup in cold storage rather than rely on a small number of devices that are all in the same building and connected to the same cloud account.
  • What happens if there’s a problem with the system or the site so that it doesn’t offer to auto-fill the passkey that I need? I’m thinking about cases where there are multiple or changing domains. It sounds like there’s no manual picker but that having one wouldn’t help because if it thinks the domain is wrong the passkey wouldn’t work, anyway.
  • This requires iCloud Keychain, yet someone may not want to put all of their passwords in iCloud. Is it practical to use a local keychain for some stuff alongside iCloud Keychain?
  • How well is this going to work in different browsers and across different platforms?

[...]

It sounds like anyone who can get into your Apple ID account and either see your phone notifications or redirect an SMS message can delete all your passkeys.

[...]

In what sense are passkeys locked to a device if they are syncing via iCloud Keychain? Is the idea that they must be on one of your devices because there is no way to export them?

Gegen aufkeimende Unsicherheit, ob passkeys wirklich die Antwort auf alle Authentifizierungsfragen sind, empfehle ich die wohltemperierte Prosa des einschlägigen Apple-Supportdokuments.

Der auf das Zusammenwirken von Apple und FIDO anspielende Titel dieses Blogposts hätte auch gut zur nostalgischen Hochstimmung rund um Clarus' Rückkehr gepasst, aber die Hundekuh und Druckdialoge im Allgemeinen interessieren mich deutlich weniger als Apples WebAuthn-Implementierung.

Targeted Release Schedule

Dass Vim 9.0 (Vim9 script!) und BBedit 14.5 (Tail Mode! finer-grained control over invisibles display!) zeitgleich (und wenige Tage nach der Abkündigung eines deutlich jüngeren Konkurrenzproduktes) veröffentlicht werden, hilft mir über die Vernachlässigung durch einen gewissen Hardware-Lieferanten hinweg.

Offline 2

Meinem Wunsch, iOS-Geräte auch ohne Netzzugang sinnvoll nutzen zu können, kommt der Webserver WorldWideWeb sehr entgegen. In der Theorie muss ich lediglich meine statische Website innerhalb meines iCloud Drive ablegen und WorldWideWeb starten, um sämtliche Seiten auch offline im Browser aufzurufen.

In der Realität scheitert das Vorhaben zunächst an der intelligenten iOS-Speicherverwaltung, die nur sehr widerwillig den Download ganzer Ordner zulässt – und WorldWideWeb findet nur lokal gespeicherte Dateien. Außerdem kämpft WorldWideWeb selbst mit dem iOS-Taskmanagement, das Hintergrundprozesse im Zweifelsfall sehr rasch beerdigt.

So bleibt auch nach vielen Jahren Offline Pages die beste Wahl für Reisen durch internetfreie Gegenden, wenn man die eigene Rezeptsammlung nicht missen möchte.

Zufallskunde

Apple erntet Anerkennung für die Re-Implementierung einer Serienbrieffunktion, zeigt aber in iOS Mail nach wie vor nicht ohne Weiteres die Empfängeradresse einer E-Mail an und entfernt Python und nano aus seinem Betriebssystem. Deutlicher kann das Unternehmen nicht machen, dass ich eigentlich nicht zu seiner Zielgruppe zähle.

Gesteuerte Digitalisierung

Meine Experimentierfreude in technischen Zusammenhängen endet bei der Steuererklärung. Weil das Elster-Projekt der Finanzbehörden bis 2013 eine Windows-Umgebung und/oder Oracle Java voraussetzte, nutze ich seit 2002 einen Online-Dienst, dessen einzige Funktion darin besteht, mich durch den Hauptvordruck und diverse Anlagen zu geleiten und anschließend ein PDF-Dokument zum Ausdruck zu generieren. Obwohl der Postversand einer unterschriebenen Steuererklärung zunehmend archaisch ist, halte ich an diesem Verfahren fest, bis die Finanzbehörden ein klares Zeichen setzen: Ab dem Veranlagungszeitraum 2021 werden papierne Erklärungen nicht mehr akzeptiert.

Zunächst versuche ich, dem vertrauten Online-Dienst ein Mandat für den Belegabruf und die digitale Übermittlung der Steuererklärung erteilen. Dieser Weg scheitert, weil ich in einem (verdrängten) Anflug von Digitalisierungsbereitschaft offenbar vor einigen Jahren bereits ein Mandat erteilt habe, das nicht zum jetzigen Projekt Steuererklärung 2021 passt (ERR-DIO-MISMATCH). Der Support des Online-Dienstes schlägt vor, das vorhandene Mandat über das Elster-Portal zu löschen. Das ist eine gute Gelegenheit, meinen elektronischen Personalausweis zum Einsatz zu bringen. Ich registriere mich mit dem Ausweis, lösche das Mandat und beantrage (innerhalb des Online-Dienstes) ein neues Mandat. Nun erscheint für mich eine neue Fehlermeldung (offener Genehmigungsantrag, ERR-APP-OPEN), während für die mit mir zusammenveranlagte Person weiterhin ERR-DIO-MISMATCH angezeigt wird.

Weil ich nun schon im Elster-Portal registriert bin, erteile ich Elster (und damit mir selbst) die Berechtigung zum Belegabruf. Der Belegabruf für die mit mir zusammenveranlagte Person funktioniert nicht, weil sie keinen elektronischen Personalausweis nutzt und die Freigabe daher über einen Schlüssel bestätigen muss, der ihr per Post zugeschickt wird. Ich kann ihre Daten allerdings auch (wie bisher beim Online-Dienst) manuell eingeben und die fertige Steuererklärung nach etwa 20 Minuten in elektronischer Form einreichen. Sogar eine Zustellung des Steuerbescheids per E-Mail wird mir in Aussicht gestellt. Wer hätte gedacht, dass mich ausgerechnet die deutschen Steuerverwaltungen zur Digitalisierung zwingen?

(Dieser Beitrag wurde auch im Techniktagebuch veröffentlicht.)

Nachtrag: Als Tierschutzverein mit stillgelegtem Postfach hätte ich vor 2022 bei meinen Elster-Aktivitäten größere Schwierigkeiten gehabt, aber die Finanzbehörden haben freundlicherweise Privatpersonen – anders als Tierschutzvereinen – eine vollständig digitale Steuererklärung erst nach der Beseitigung aller potentiellen Hürden abverlangt.

Backup 2022

Nach mehreren Ermahnungen auf Twitter ergänze ich meine allzu optimistische Datensicherung um einen weiteren Server für das CoreBackup und verschiebe das verschlüsselte CoreBackup.sparsebundle nach /Users/jan/Library/Mobile Documents/com~apple~CloudDocs, auf dass ein auf Europa begrenzter nuklearer Krieg meine Daten nicht hinwegfegt.

Schlüsseldienst

Ab einer bestimmten Anzahl von PGP-Schlüsseln wird die manuelle Veröffentlichung in einem Web Key Directory unpraktikabel. Das GnuPG-Paket enthält daher mit gpg-wks-client ein Werkzeug, das eine automatische Veröffentlichung ermöglicht. Ich beschränke mich auf die lokale Generierung der erforderlichen Dateien mit der Option --install-key. Durch den Aufruf –

gpg --list-options show-only-fpr-mbox -k '@eden.one'

– kann man den Input für gpg-wks-client erzeugen. Der Befehl liefert eine Liste von Fingerprints und UIDs für alle Schlüssel, in denen mindestens eine UID das Muster @eden.one enthält. Wenn also die Schlüssel weitere Domains erfassen, genügt @eden.one als einigendes Band. Allerdings werden so bekanntlich auch Schlüssel mit dem Status expired oder revoked berücksichtigt. Das Ergebnis muss daher durch einen invertierten grep-Aufruf laufen, der den unerwünschten Schlüssel ausfiltert:

gpg --list-options show-only-fpr-mbox -k '@eden.one' | grep -v xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | gpg-wks-client -v --directory /var/www/html/site/.well-known/openpgpkey --install-key

Im Prinzip ließen sich beliebig viele grep-Aufrufe verketten, aber in der Praxis ist dieser Workaround nur für einen oder zwei ungültige Schlüssel hilfreich. Das Ergebnis der obigen Befehlskette ist jedenfalls eine Ordnerstruktur für die fortgeschrittene WKD-Methode, und so verzichte ich schweren Herzens auf die direkte WKD-Methode und passe nginx.conf entsprechend an. Dank gpg-wks-client ist die dreijährliche Verlängerung von Schlüssellaufzeiten (mit dem expire-Kommando) nun auch unter WKD-Aspekten handhabbar.

Authentisch gesichert

Zwar gibt es keinen Grund, an der Authentizität meiner Backup-Benachrichtigungen zu zweifeln, aber nach der Wiedereingliederung von OpenPGP in den Mailstack möchte ich natürlich auch skriptbasierte E-Mails signieren. Um wohlgeformte E-Mails des MIME-Typs multipart/signed zu versenden, beschäftige ich mich noch einmal sehr intensiv mit den passenden Python-Modulen, akzeptiere nach einigen erfolglosen Bemühungen, dass das aktuelle API fehlerhaft/ungeeignet ist und verwende das legacy API auf Basis eines 10 Jahre alten Code-Schnipsels. Die Schmach wird etwas gemildert durch das Eingeständnis der Python-Dokumentation, dass mindestens email.mime nicht völlig überholt ist:

This module is part of the legacy (Compat32) email API. Its functionality is partially replaced by the contentmanager in the new API, but in certain applications these classes may still be useful, even in non-legacy code.

Das Versandskript benötigt neben diversen email-Modulen natürlich python-gnupg:

#!/usr/bin/env python3 import os import datetime import __main__ as main import smtplib from email.message import Message from email.mime.multipart import MIMEMultipart from email import charset from email.utils import make_msgid import keyring import gnupg smtp_server = 'mail.eden.one' smtp_user = 'user@eden.one' port = 587 localhost = 'client.eden.one' pgp_entry = 'PGP' pgp_user = pgp_entry def send_message(subject, body): now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') subject = f'{os.path.basename(main.__file__)}: {subject}' body = f'{body}\n\n{now}' basemsg = Message() basemsg.set_payload(body, charset='utf-8')

Ohne den Parameter charset an dieser Stelle besteht basemsg nur aus dem Inhalt der Variablen body, die Angabe eines character sets erzeugt dagegen ein vollwertiges MIME-Objekt:

MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 VGV4dCBtaXQgw5xtbMOkdXRlbi4=

Nun ist es so, dass mutt (u.a. im Zusammenhang mit dem Parameter pgp_strict_enc zur obligatorischen Kodierung von Nachrichten mit trailing whitespace), der RFC 2045 für Text –

The Quoted-Printable encoding is intended to represent data that largely consists of octets that correspond to printable characters in the US-ASCII character set. [...] The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.

Rspamd sowie der RFC 2015 (etwas weniger deutlich sein Nachfolger RFC 3156) –

Though not required, it is generally a good idea to use Quoted-Printable encoding in the first step (writing out the data to be signed in MIME canonical format) if any of the lines in the data begin with "From ", and encode the "F". This will avoid an MTA inserting a ">" in front of the line, thus invalidating the signature!

– die platzsparende Kodierung quoted-printable bevorzugen. Um mich nicht des verschwenderischen Umgangs mit Speicherplatz und Bandbreite bezichtigen lassen zu müssen, erweitere ich das Skript um ein entsprechendes Charset()-Objekt und den charset-Parameter

base_charset = charset.Charset('utf-8') base_charset.body_encoding = charset.QP basemsg = Message() basemsg.set_payload(body, charset=base_charset)

– und erhalte:

MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Text mit =C3=9Cml=C3=A4uten.

Dasselbe Ergebnis erzielt man übrigens auch, wenn man basemsg das Charset()-Objekt nicht im Rahmen von set_payload(), sondern nachträglich zuweist (basemsg.set_charset = base_charset). Eine vorzeitige Zuweisung führt dagegen wieder zu einer base64-Kodierung, weil set_payload() den Effekt von set_charset überschreibt (anders als bei MIMEText()-Objekten, die mit vorzeitigen replace_header()- und set_charset()-Anweisungen offenbar besser umgehen können). Weiter im Skript:

basetext = basemsg.as_string().replace('\n', '\r\n')

Hier sind sich RFC 2015 und RFC 3156 einig:

The data to be signed MUST first be converted to its content-type specific canonical form. For text/plain, this means conversion to an appropriate character set and conversion of line endings to the canonical <CR><LF> sequence.

Nun muss eine Signatur erzeugt und in ein Message()-Objekt umgewandelt werden:

gpg = gnupg.GPG(gpgbinary='/opt/homebrew/bin/gpg') pgp_passphrase = keyring.get_password(pgp_entry, pgp_user) signature = str(gpg.sign(basetext, keyid='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', passphrase=pgp_passphrase, detach=True)) signmsg = Message() signmsg['Content-Type'] = 'application/pgp-signature; name="signature.asc"' signmsg['Content-Description'] = 'OpenPGP digital signature' signmsg.set_payload(signature)

Der Parameter gpgbinary für gnupg.PGP() ist bei einem Aufruf des Skriptes über eine Shell mit wohlgefülltem $PATH tückischerweise entbehrlich, aber spätestens bei der Einbettung via launchctl zwingend erforderlich. Schließlich werden die beiden Message()-Objekte in einem MIMEMultipart()-Objekt zusammengeführt:

msg = MIMEMultipart(_subtype="signed", micalg="pgp-sha512", protocol="application/pgp-signature") msg.attach(basemsg) msg.attach(signmsg) msg['From'] = 'Sender <sender@eden.one>' msg['To'] = 'Recipient <recipient@eden.one>' msg['Subject'] = subject msg['Message-ID'] = make_msgid(domain=localhost) smtp_password = keyring.get_password(smtp_server, smtp_user) s = smtplib.SMTP(host=smtp_server, local_hostname=localhost, port=port) s.starttls() s.login(smtp_user, smtp_password) s.send_message(msg) del msg

Der Datenverkehr wächst durch die Signatur und den MIME-Overhead je Nachricht (dank quoted-printable nur) um rund 600 Bytes, aber im Gegenzug gewährt Rspamd ein zusätzliches Symbol (SIGNED_PGP (-2)). Und ich kann sicher sein, dass mir niemand ein erfolgreich durchgeführtes Backup vorgaukelt.

Sommerputz

Dank der Entkopplung von Homebrew und uwsgi ist ein Update der Homebrew-Pakete (brew update; brew upgrade) kein Grund zur Nervosität mehr, auch wenn uwsgi wegen der veränderten Umgebung neu gestartet werden muss:

snafu % launchctl unload -w ~/Library/LaunchAgents/localhotel.snafu.uwsgi.plist snafu % launchctl load -w ~/Library/LaunchAgents/localhotel.snafu.uwsgi.plist

Allerdings benötigt das erneuerte Python frische Zugriffsrechte auf meinen Schlüsselbund, andernfalls scheitern alle Skripte, die das keyring-Modul verwenden.