Irgendwie frustriert einen der aktuelle Zustand unserer Kryptographie-Softwarelandschaft. Einerseits möchte man es dem Nutzer so einfach wie möglich machen, andererseits aber einem Angreifer so schwierig wie möglich. Prinzipiell sind alle hier gängigen Bibliotheken, sei es OpenSSL, GnuTLS, NSS, NaCl und die diversen OpenPGP-Implementierungen zwar an sich einig, wie die verschiedenen kryptographischen Verfahren umzusetzen sind, aber in den Details stecken so einige Stolpersteine, die einfach nicht sein müssen.
Bereits relativ früh fiel mir hierbei ein Limit in allen PGP-Implementierungen auf, welches in keinem einzigen der relevanten Standards (RFC 1991, RFC 2440, RFC 4880) erwähnt wird, aber irgendwie dennoch – fast wie abgeschrieben – in jeglichen Implementierungen wie als wäre es im Standard fix festgeschrieben wieder auftaucht: Maximale Schlüssel-Länge 4096 Bit RSA, 4096 Bit DSA (früher sogar nur 1024 Bit) und ECC basierend auf der verwendeten Kurve. Nutzt man einen ElGamal-Subschlüssel (besser bekannt als „Signaturschlüssel für DSA“) wird sogar plötzlich nur 3072 Bit verwendet.
Nun stammen zahlreiche OpenPGP-Implementierungen aus den Urzeiten der ersten Crypto-Kriege, in denen die Verwendung starker Verschlüsslungsalgorithmen verpöhnt und doch bitte der Generalschlüssel bei der Regierung zu hinterlegen war; aber diese Zeiten haben wir doch hoffentlich endlich hinter uns gelassen. Auch das Argument, der damals deutlich rechenleistungsärmeren Computer – laut Moore’s Law immerhin nur ein Millionstel dessen, was vergleichbare Technik heute leistet – kann unmöglich als legitime Rechtfertigung akzeptiert werden.
Ja, damals™ war alles besser, aber die begrenzte Schlüssellänge schon aus Rücksichtnahme auf den eigenen Rechner anzuraten. Und das hat jeder halbwegs klar denkende Nutzer schon von sich aus beherzigt: Man hat damals deutlich gemerkt, dass gerade mit dem asymmetrischen Schlüssel gearbeitet wurde. Das Argument, dass man mit langen Schlüsseln also einen Denial of Service-Angriff fahren kann, stimmt somit nur bedingt. Zumal: Dann sollte sich diese Schranke doch eher an der Rechenleistung des Systems orientieren, statt für alle Ewigkeiten in irgendwelchen Code-Leichen zu lauern.
Interessant ist mindestens bei GnuPG, dass es nicht ein solches Limit gibt, sondern gleich zwei unterschiedliche: Während das eine Limit einzig bei der Schlüsselgenerierung erzwungen wird und bei 4096 Bit seit Ewigkeiten festgeschrieben ist, wird das andere Limit nicht etwa beim Rechnen mit großen Zahlen, also dann wenn wirklich Zeit benötigt wird, geprüft, sondern beim Lesen und Schreiben eben solcher überlangen Zahlenkolonnen; also in dem Moment, wenn die Schlüsselgenerierung bereits tagelang Rechenleistung verbraten hat und somit nach Abschluss dieser Arbeiten das Ergebnis in die Mülltonne befördert.
Eine andere irrwitzige Beschränkung dieser Kategorie findet sich in OpenSSL, wie ich leidlich feststellen musste, als ein SSL-Assessment-Test fehlschlug, beim Versuch, die 13337 Bit umfassenden DH-Parameter auszuhandeln. Nein, nicht wegen eines Timeouts, sondern wegen – gut geraten – einem fest kodierten Limit der Maximal-Länge von 10000 Bit. Ein Limit was übrigens an lediglich einer Stelle definiert, und auch nur an exakt einer Stelle geprüft wird. Die Stelle der Prüfung findet man in OpenSSL übrigens auch nur anhand der Fehlermeldung, aber das ist eher ein Problem der Code-Qualität von OpenSSL, über die man besser nicht reden sollte.
Qualität liefert an dieser Stelle übrigens auch die Implementierung von GnuPG bei der Sicherung des Private Keys, die beschränkt durch ein ewig niedriges Limit von 32KiB „sicherem Speicher“ unter Linux beim kleinsten Hustenanfall mit einem halbwegs „sicheren“ Schlüssel gleich Schreikrämpfe bekommt, das zu wenig Platz da sei. Oder anders ausgedrückt: Entweder man vertraut seinem Rechner eh von Haus aus – dann brauch man diese Farce mit gesichertem Speicher nicht – oder man muss dieses Feature abschalten: Was einem nur in der Form gelingt, dass man ihm mitteilt, dass er doch soviel „sicheren Speicher“ initialisieren soll, dass er der Meinung ist, dass es keinen gäbe und er daher mit einer Warnmeldung dennoch fortsetzt. Versucht man an der Stelle die direkte Deaktivierung, verweigert GnuPG den Dienst komplett.
Ein anderes interessantes Speicherproblem hat an dieser Stelle auch Mozilla in seiner NSS-Implementierung im Angebot, was aus drei Gründen sehr bemerkenswert ist: 1. es ist konstant reproduzierbar, 2. es ist Abhängig von der Schlüssel-Operation und 3. es ist vollkommen unlogisch. Aber der Reihe nach, denn dieses Problem braucht etwas Erklärung. Wie einige sicherlich festgestellt haben, verwendet dieser Blog SSL. SSL ist dieser Krypto-Foo mit Zertifikaten, was einmal zum Absichern von 50-Dollar-Transaktionen entworfen wurde. Nunja, eben dieses SSL wird auf diesem Server mit einem X.509-Zertifikat mit einem 8192-Bit-RSA-Schlüssel verwendet. Kein Problem, braucht 2KiB, ggf. 8KiB RAM für ein paar Potenzierungsoperationen, aber ist sonst nicht der Rede wert. Außer man versucht sich mit eben jenem Schlüssel in Form eines Client-Zertifikates bei einer Website zu authentifizieren. Das führt reproduzierbar zu einem Out-of-Memory-Fehler, und zwar nicht erst bei 8192 Bit, sondern exakt bei allem, was mindestens ein Bit mehr als 4096 Bit RSA hat. Wäre die Grenze wenigstens bei irgendetwas krummen, könnte man das ganze mit wirklicher Speichernot erklären, wobei selbst dann das WTF bleibt, warum man nur so wenig gesicherten Speicher verfügbar hat. Ach ja: Gleiches Zertifikat im Thunderbird für Email-Signaturen eingesetzt läuft übrigens reibungslos. Und bevor das Argument mit krummen Schlüssellängen kommt, sei noch erwähnt, dass es mit 4095 Bit reibungslos funktioniert.
Aber eines muss man Firefox an dieser Stelle lassen: Im Gegensatz zu diversen Apple-Produkten erhält man wenigstens eine klare Fehlermeldung; wenn auch keine wirklich hilfreiche. Auf Apple sieht das Ganze etwas anders aus: Hier reicht ein Besuch des Blogs in der Regel bereits aus, um Safari auf die Reise ins Nirvana zu schicken. Und da Apple an dieser Stelle eine konsistente User Experience bietet, geschieht dies konsequent auch auf iOS 6-Devices, was sich sowohl mit dem iPhone, als auch einem iTamponPad reproduzieren ließ. Auf iOS 7 gab es zwischenzeitlich sogar einmal Besserung: Nein, die Krypto hat nicht einfach mal ihren Dienst getan, zumindest nicht so, dass ein Nutzer hätte etwas damit anfangen können. Der Fortschritt bestand hier vielmehr darin, dass es iOS 7 geschafft hat, dem Nutzer das Zertifikat der Website zu päsentieren, bevor es – nach dessen Überprüfung und Akzeptanz – eine Endlos-Schleife mit Page-Reloads angetreten hat.
Nun bin ich absolut kein Freund von Apple oder Safari, aber einfach nur zu sagen Safari ist hier kaputt würde die Sache etwas sehr stark vereinfachen. Vielmehr haben wir hier ein Problem in der Krypto-Lib von iOS am Hals, was sich auch an anderer Stelle wunderbar zeigt. Denn wir alle mögen Mails, diese kleinen RFC-822-formatierten Text-Konglomerate die zu 90% Spam und 10% anderen Bullshit enthalten. Manchmal verirrt sich hier auch eine sinnvolle Mail darunter, was oft dadurch erkennbar wird, dass diese Mails eine Signatur tragen. Solche Signaturen sind praktisch. Manchmal findet man diese auch auf Mailing-Listen. Zu dumm nur, wenn der Mail-Client der Wahl aus Versehen immer dann abstürzt, wenn man versucht, die Mail zu lesen, zu verschieben, zu löschen oder anderweitig irgendetwas mit dieser Mail anzufangen.
Und alle diese Dinge waren komplett von den passenden Standards gedeckelt, oder basierend auf der zugrundeliegenden Mathematik vollständig legitim, was umso interessanter wird, wenn man sich einmal eine Reihe von Standards anschaut, die Rahmenbedingungen für diverse Verschlüsslungsverfahren festlegen. Denn wer hat sich noch nicht gewundert, warum in Public Keys bei RSA immer 65537 vorkommt (naja, außer bei so ein paar Schlüsseln von mir) und man nicht der mathematischen Grundlage folgt, nach der e einfach nur teilerfremd zu sowohl p als auch q sein muss? Hier gibt es prinzipiell zwei Antworten, wobei die eine primär die Wahl der Zahl erklärt – was eine reine Performance-Entscheidung darstellt -, während die andere zu einem NIST-FIPS-Standard führt, der festlegt, dass e mindestens 65537 (zur Vermeidung von einigen Angriffen) aber maximal 2^256-1 sein darf. Womit wir an der Stelle wären, wo der Standard einfach keinen Sinn ergibt: Ja, man möchte ein Limit haben, aber dieses ist primär dadurch begründet, dass bei großen Exponenten die Wahrscheinlichkeit für d < < e deutlich zunimmt; liest man hierzu die passende Literatur, ergibt sich ein sinnvolles Limit bei ungefähr 70% des Modulus n, was selbst bei moderaten 4096er Schlüsseln bereits 2^3072-1 ergibt – AKA eine Zahl, die 10 mal so lang ist.
Mangels passenden Utilities konnte ich noch nicht prüfen, wieviel kaputte Krypto-Software den Public Exponenten als Gott-gegeben mit 65537 annimmt, aber so wie das bisher ausschaut, würde es mich nicht verwundern, wenn mit entsprechenden Schlüsseln noch eine ganze Menge Software den Geist aufgibt.
Was mich zu meinem Punkt an dieser Stelle bringt: Wann hören die Leute endlich auf, die Standards wörtlich zu implementieren, frei von jeglichem Verstand der darunterliegenden Verfahren? Ja, es ist ein absolutes Desaster, wenn man zufällig uninitialisierte Speicherzugriffe patcht oder gleich die Backdoor im PRNG platziert, aber warum muss dann bitte schön die Funktionalität künstlich beschränkt werden, nur weil der Geheimdienst des eigenen Misstrauens sonst nicht ausreichend mitlesen kann?
Macht Krypto bitte endlich einmal richtig!
AAAH-CHOO!