etis GmbHAlle Artikel
IT-Service Hands-on

Warum sich ein Mac nicht per IKEv2 an OpenBSD iked anmelden kann – und wie eine Zeile im Quelltext das löst

Zertifikats-VPN mit OpenBSD iked: Windows und Linux verbinden, macOS scheitert mit „Authentication failed“. Die Ursache ist eine nicht normgerechte ECDSA-Signatur von Apples IKEv2-Client, die iked ablehnt. Fehlersuche, Beweis aus dem Apple-Log und Korrektur im Quelltext.

etis GmbH6 Min. Lesezeit

Wir betreiben für unsere Arbeitsplätze ein Zertifikats-VPN auf Basis von IKEv2. Als Gateway dient iked aus dem OpenBSD-Basissystem, die Zertifikate kommen aus unserer eigenen PKI, durchgängig mit ECDSA auf der Kurve P-384. Windows (nativer IKEv2-Client mit Rechnerzertifikat) und Linux (strongSwan) verbinden sich damit ohne Umwege. Der erste Mac tat es nicht. Dieser Beitrag beschreibt, wie wir die Ursache gefunden haben, warum sie nicht in der Konfiguration liegt und was im Quelltext von iked zu ändern ist. Wer Apple-Clients an ein OpenBSD-Gateway hängen will, spart sich damit vermutlich einen Abend.

Das Symptom

Das Profil für macOS (.mobileconfig mit Root-CA, Zwischen-CA, PKCS#12-Identität und einer IKEv2-Verbindung mit CertificateType = ECDSA384) ließ sich sauber installieren. Beim Verbinden meldete macOS nur „Authentifizierung fehlgeschlagen“. Das Gateway protokollierte:

ikev2_auth_verify: ikev2_msg_authverify failed
ikev2_send_auth_failed: authentication failed for UFQDN/user@example.com
ikev2_send_auth_failed: issuer: /C=DE/O=Example/CN=Example VPN CA

Bemerkenswert daran: iked hatte das Client-Zertifikat bereits erfolgreich gegen Kette und Sperrliste geprüft. Die Policy passte, die Pool-Adresse war zugeteilt, die Traffic-Selektoren ausgehandelt. Erst der letzte Schritt scheiterte, die Prüfung der Signatur im AUTH-Payload. Und zwar ohne weitere Begründung, auch nicht mit ikectl log verbose.

Der Irrweg über RSA

Der naheliegende Verdacht war eine Inkompatibilität bei ECDSA. Also ein zweites Profil mit einem RSA-4096-Zertifikat und CertificateType = RSA. Ergebnis: Das Gateway nahm die Signatur des Mac jetzt an, dafür brach der Mac ab. Apples Client schrieb in sein Protokoll:

Initiator packet authentication method DigitalSignatureECDSA256
is not compatible with configuration RSASignature

Das ist die erste Lehre: Apples IKEv2-Client verlangt vom Gateway dieselbe Signaturfamilie, die im Profil als CertificateType steht. Ein RSA-Profil funktioniert nur gegen ein Gateway mit RSA-Schlüssel. Wer sein Gateway, wie wir, mit einem P-384-Schlüssel betreibt, muss das ECDSA-Problem lösen und kann es nicht umgehen.

Der Beweis aus dem Apple-Log

Ohne Testgerät kommt man hier nicht weiter. Wir haben für einen Tag einen Mac mini in der Cloud gemietet und das Profil dort installiert. Apples Netzwerkerweiterung protokolliert jeden IKE-Austausch im Klartext, abrufbar mit:

log show --last 15m --info --predicate 'process == "NEIKEv2Provider"'

Darin steht der AUTH-Payload, den der Mac verschickt:

Authentication Protocol = ECDSA384
Authentication Data = {length = 208, bytes = 0x00000000 00000000 00000000 00000000 ... }

Das ist die Ursache. RFC 4754 legt für ECDSA-384 fest, dass die beiden Signaturwerte r und s je genau 48 Byte lang sind, zusammen 96 Byte, bei Bedarf vorn mit Nullen aufgefüllt. Apple schickt 208 Byte, die mit einer langen Folge von Nullen beginnen. Das sind r und s zu je 104 Byte, und 104 ist genau die maximale Länge einer DER-kodierten P-384-Signatur. Apple nimmt offenbar die DER-Maximalgröße als Breite der beiden Werte. Mathematisch ist das harmlos, die Zahlen sind nur mit Nullen verlängert. Normgerecht ist es nicht.

Warum fällt das sonst niemandem auf? strongSwan, das Gateway hinter den meisten Anleitungen für Apple-Clients, teilt die empfangenen Daten einfach in zwei Hälften und übergibt sie an BN_bin2bn(), das führende Nullen ignoriert. iked prüft vorher die Länge.

Die Ursache im Quelltext

In sbin/iked/crypto.c wandelt _dsa_verify_prepare() das rohe r|s in das DER-Format um, das libcrypto zum Prüfen braucht. Davor steht ein Vorfilter:

	case IKEV2_AUTH_ECDSA_256:
	case IKEV2_AUTH_ECDSA_384:
	case IKEV2_AUTH_ECDSA_521:
		/* ... */
		if (*lenp < 64 || *lenp > 132 || *lenp % 2)
			goto done;
		bnlen = (*lenp)/2;
		/* sigp points to concatenation: r|s */
		if ((obj = ECDSA_SIG_new()) == NULL ||
		    (r = BN_bin2bn(*sigp, bnlen, NULL)) == NULL ||
		    (s = BN_bin2bn(*sigp+bnlen, bnlen, NULL)) == NULL ||
		    ECDSA_SIG_set0(obj, r, s) == 0 ||
		    (len = i2d_ECDSA_SIG(obj, &ptr)) <= 0)
			goto done;

Die Obergrenze 132 ist die Länge von r|s bei P-521 (2 × 66 Byte). Apples 208 Byte liegen darüber, goto done liefert −1, und der Aufrufer meldet nur „authentication failed“. Es gibt keine Protokollzeile für diesen Fall und keinen Schalter in iked.conf. Auch ikeauth ecdsa384 ändert nichts, weil der Prüfpfad derselbe bleibt.

Die Korrektur

Die Längenprüfung ist ein Plausibilitätsfilter, kein Sicherheitsmerkmal. Nach der Halbierung werden r und s DER-kodiert und von EVP_DigestVerifyFinal() gegen die Kurvenordnung geprüft; ein zu großes oder falsches r oder s scheitert dort. Es reicht deshalb, die Obergrenze anzuheben:

--- sbin/iked/crypto.c
+++ sbin/iked/crypto.c
@@ -1149,7 +1149,7 @@
 		 * buffer (we cannot override the given buffer) and the caller
 		 * has to free this buffer ('freeme').
 		 */
-		if (*lenp < 64 || *lenp > 132 || *lenp % 2)
+		if (*lenp < 64 || *lenp > 512 || *lenp % 2)
 			goto done;
 		bnlen = (*lenp)/2;
 		/* sigp points to concatenation: r|s */

Der Wert 512 begrenzt weiterhin die Speichermenge und lässt alle drei Kurven mit Apples Auffüllung durch. Eine strengere Variante würde die erwartete Breite aus der Kurve des Schlüssels ableiten und nur dann längere Daten akzeptieren, wenn die überzähligen Bytes Nullen sind. Für den Betrieb ist die einfache Form ausreichend, weil die eigentliche Prüfung ohnehin in libcrypto stattfindet.

So haben wir das Binary gebaut und eingespielt, auf OpenBSD 7.9:

# Quellen des Release, Signatur prüfen, nur sbin/iked entpacken
ftp https://cdn.openbsd.org/pub/OpenBSD/7.9/{SHA256.sig,src.tar.gz}
signify -C -p /etc/signify/openbsd-79-base.pub -x SHA256.sig src.tar.gz
mkdir -p /tmp/src && tar xzf src.tar.gz -C /tmp/src sbin/iked

# Errata-Quellpatches für iked (009, 027), ebenfalls signiert
cd /tmp/src && patch -p0 < 009_iked.patch && patch -p0 < 027_iked.patch

# Patch, Bau, Prüfung, Sicherung, Installation
cd sbin/iked && patch -p0 < crypto.c-apple-ecdsa.diff && make
doas ./iked -n                                   # configuration OK
doas cp -p /sbin/iked /sbin/iked.orig-7.9
doas install -o root -g bin -m 555 iked /sbin/iked
doas rcctl restart iked

Vorher syspatch bis zum aktuellen Stand, sonst überschreibt ein späterer Errata-Patch das eigene Binary wieder mit der alten Prüfung. Der Rückweg ist die gesicherte Datei. Und weil ein Systemupdate das Binary jederzeit ersetzen kann, prüft unser Monitoring seitdem die Prüfsumme von /sbin/iked.

Das Ergebnis: Der Mac verband sich beim nächsten Versuch sofort, mit P-384 wie alle anderen Clients. Wir haben den Fehler mit dem Patch an das OpenBSD-Projekt gemeldet; sobald eine Korrektur im Basissystem landet, entfällt der eigene Bau.

Drei Nebenbefunde für Apple-Profile

Auf dem Weg dorthin sind wir über drei weitere Eigenheiten gestolpert, die jedes Profil für Apple-Clients betreffen:

  • PKCS#12 nur im alten Format. Apples Importer lehnt Container ab, die OpenSSL 3 standardmäßig erzeugt (AES-256-CBC, PBKDF2, SHA-256-MAC), und meldet dann „Passwort falsch“. Es muss pbeWithSHA1And3-KeyTripleDES-CBC mit SHA-1-MAC sein, bei OpenSSL der Schalter -legacy. Die Sicherheit trägt dann das Passwort, nicht die Verpackung.
  • Kein Split-Tunnel im Profil. Der Apple-Client kennt keine Client-Routen. Welche Netze durch den Tunnel gehen, bestimmen allein die Traffic-Selektoren, die das Gateway zurückgibt. Bei iked heißt das: mehrere from <netz> to dynamic-Zeilen in der Policy statt from any. Der Mac installiert daraus genau die Routen und lässt die Default-Route auf dem lokalen Interface.
  • Kein RFC 7427. Apple kündigt zwar Hash-Algorithmen für die Signaturauthentifizierung an, nutzt dann aber die klassischen Methoden: RSA mit SHA-1 oder ECDSA nach RFC 4754. Wer sich wundert, warum ein Gateway mit RFC 7427 signiert und der Mac trotzdem ECDSA-256 im Log nennt, sieht hier die Erklärung.

Fazit

Die Konfiguration war von Anfang an richtig. Dass es trotzdem nicht ging, lag an zwei Implementierungen, die beide auf ihre Weise konsequent sind: Apple füllt Signaturen breiter auf, als die Norm vorsieht, und iked lehnt ab, was nicht in den Normrahmen passt. Ohne das Client-Log auf einem echten Mac wäre die Ursache nicht zu finden gewesen; das Gateway sieht nur „authentication failed“. Wer Apple-Clients an OpenBSD betreiben will, braucht bis zu einer Korrektur im Basissystem den gezeigten Patch, oder ein Gateway mit RSA-Schlüssel, was den übrigen Clients eine Umstellung aufzwingt. Die eine Zeile ist der kleinere Eingriff.

#openbsd#iked#ikev2#macos#vpn#ecdsa#pki#fehlersuche