DNS SRV-Records und Zertifikate

Das Problem

Für eine Erklärung wie srv-Einträge funktionieren und was das ist siehe hier: /posts/short_introduction_srv-records

_sip._tls.example.com. 3600 IN SRV 0 100 4866 sip1.example.com.

Bei SRV-Einträgen hat der Client nach der Auflösung des Namens mind. 2 Domain-Namen für einen Dienst.
Den ursprünglichen, den er konfiguriert bekommen hat/aus einer URI abgeleitet hat und aus dem er dann den SRV-Namen gebaut hat → example.com.
Den aus der Auflösung des SRV-Eintrags → sip.example.com.

Die Frage ist jetzt welchen erwartet er/muss er erwarten im Zertifikat zu sehen wenn er sich per TLS mit dem Dienst verbindet?

"Kurze" Antwort

In der Regel muss im Zertifikat als dNSName(1) (OpenSSL: DNS) in der Extension 'SubjectAltName' (OpenSSL: 'X509v3 Subject Alternative Name') der "origin"(2) Domain-Name angegeben sein (in obigem Beispiel 'example.com').
Also NICHT der Host-Name in den der SRV-Eintrag auflöst/FQDN des Servers auf dem der Dienst läuft (wie z.B. 'server1.example.com')!

Je nach Anwendungsprotokoll (also SIP, IMAP, SMTP, XMPP usw.) können theoretisch weitere Felder verlangt werden (XMPP verlangt z.B. SRV-Einträge im Zertifikat wenn SRV-DNS-Einträge für die Auflösung genutzt werden) und es ist theoretisch auch möglich das ein Protokoll von oben stehender Regel abweicht, so es die Authentizität/Echtheit der in der Folge aufgelösten Domain-Namen sicherstellen kann.
Die entsprechenden Regeln stehen in entsprechenden RFC/Standards der Protokolle.

In der Praxis reicht oftmals der "origin"(2) Domain-Name in dNSName/DNS-Eintrag in SubjectAltName, auch wenn das Protokoll weitere Einträge (wie SRV) vorschreibt.

Daneben gibt es noch Ausnahmen: "Kaputte" Clients die tatsächlich den Host-Namen in den der SRV-Eintrag auflöst sehen wollen - das ist in nahezu immer ein Fehler im Client. Diese lassen sich (wenn es nicht anders geht) per Wildcard-Zertifikat einfangen → dNSName '*.example.com'
Tollerante Clients die sowohl den 'origin" Domain-Name, als auch den Hostname aus dem srv-Eintrag akzeptieren → die sind ggf. theoretisch ein Sicherheitsrisiko → weiteres siehe im weiteren Text.


  • (1) dNSName ist der FQDN den man mindestens bei jeder Zertifikatserstellung (bei Server-Zertifikaten) angeben muss - also nichts spezielles/ dass was auch letsencrypt abfragt

  • (2) "origin" DNS-Name meint den Domain-Namen den der Client fest konfiguriert hat/aus anderen fest konfigurierten Daten wie E-Mailadresse shellkraut@example.com → example.com ableiten kann.

Wo steht das/ woraus ergibt sich das?

RFC 9525 - "Service Identity in TLS" (https://www.rfc-editor.org/rfc/rfc9525)

6.1. Constructing a List of Reference Identifiers

6.1.1. Rules

The client MUST construct a list of acceptable reference identifiers and MUST do so independently of the identifiers presented by the server.

The inputs used by the client to construct its list of reference identifiers might be a URI that a user has typed into an interface (e.g., an HTTPS URL for a website), configured account information (e.g., the domain name of a host for retrieving email, which might be different from the DNS domain name portion of a username), a hyperlink in a web page that triggers a browser to retrieve a media object or script, or some other combination of information that can yield a source domain and an application service type.

D.h. die Liste der Referenz-Identifiers (aka. Domain-Namen oder IP-Adressen die in einem Zertifikat akzeptiert würden) müssen auf dem Client gebildet werden.
Der Mechanismus kann verschiedene Daten einbeziehen, wie den Domain-Teil aus User-IDs → janedoe@example.com → example.com. Er kann Informationen heranziehen wie den "Application Service Type", also zum Beispiel das es sich um einen IMAP-Account handelt.

During the course of processing, a client might be exposed to identifiers that look like, but are not, reference identifiers. For example, DNS resolution that starts at a DNS-ID reference identifier might produce intermediate domain names that need to be further resolved. Unless an application defines a process for authenticating intermediate identifiers in a way that then allows them to be used as a reference identifier (for example, see [SMTP-TLS]), any intermediate values are not reference identifiers and MUST NOT be treated as such. In the DNS case, not treating intermediate domain names as reference identifiers removes DNS and DNS resolution from the attack surface.

Oben stehendes besagt explizit, dass Domain-Namen oder IP-Adressen (aka. Identifiers) die sich im Laufe der Auflösung u.a. über DNS ergeben, nicht als Referenz-Identifier herangezogen werden dürfen.
D.h. Das Ergebnis der Auflösung eines SRV-Records, also der Hostname oder IP-Adresse dürfen nicht zum Vergleich mit einem Zertifikat herangezogen werden, da sie sich aus der Auflösung im DNS ergeben und dem Client vorher nicht bekannt waren.
Hingegen kann der SRV-Record-FQDN, also '_imap._tsl.example.com' gegen ein Zertifikat geprüft werden, da dieser vom Client erstellt wurde/aus Daten besteht die dem Client bekannt waren und nicht durch Auflösung im DNS entstanden ist.
Die Ausnahme ist, dass die Anwendung einen Weg zur Verfügung stellt die Echtheit (Authentication) der Zwischenauflösungen sicherstellt - das ist dann Application-Prokoll-spezifisch.

Which identifier types a client includes in its list of reference identifiers, and their priority, is a matter of local policy. For example, a client that is built to connect only to a particular kind of service might be configured to accept as valid only certificates that include an SRV-ID for that application service type. By contrast, a more lenient client, even if built to connect only to a particular kind of service, might include SRV-IDs, DNS-IDs, and IP-IDs in its list of reference identifiers.

Die Auswahl der Referenz-Identifier die der Client in einem Zertifikat mindestens sehen will, bleibt den lokalen Anforderungen bzw. häufig der Software die den Client implementiert überlassen.
Es kann also sein das es ausreicht das der eigentliche Domain-Name in dNSName (OpenSSL: DNS) in der Extension 'SubjectAltName' steht, obwohl zum finden des eigentlichen Hosts ein SRV-Record aufgelöst wurde, es kann aber auch sein das die Implementierung zusätzlich den SRV-Record im srv-Feld in der 'SubjectAltName'-Sektion sehen will.
Teilweise spezifiziert auch das Application-Protokoll was genau im Zertifikat vorhanden sein muss.

Sektion "6.2 Preparing to Seek a Match" definiert dann im weiteren wo welche Referenz-Identifier im Zertifikat zu finden sind:

A DNS-ID reference identifier MUST be used directly as the DNS domain name, and there is no application service type.
An IP-ID reference identifier MUST exactly match the value of an iPAddress entry in subjectAltName, with no partial (e.g., network-level) matching. There is no application service type.
For an SRV-ID reference identifier, the DNS domain name portion is the Name and the application service type portion is the Service. For example, an SRV-ID of _imaps.isp.example has a DNS domain name portion of isp.example and an application service type portion of imaps, which maps to the IMAP application protocol as explained in [EMAIL-SRV].
For a reference identifier of type URI-ID, the DNS domain name portion is the "reg-name" part of the "host" component and the application service type portion is the scheme, as defined above. Matching only the "reg-name" rule from [URI] limits the additional domain name validation (Section 6.3) to DNS domain names or non-IP hostnames. A URI that contains an IP address might be matched against an IP-ID in place of a URI-ID by some lenient clients. This document does not describe how a URI that contains no "host" component can be matched. Note that extraction of the "reg-name" might necessitate normalization of the URI (as explained in Section 6 of [URI]). For example, a URI-ID of <sip:voice.college.example> would be split into a DNS domain name portion of voice.college.example and an application service type of sip (associated with an application protocol of SIP as explained in [SIP-CERTS]).

Die nachfolgenden Sektionen des RFC beschreiben dann im Detail wie die Überprüfung der einzelnen Felder genau zu erfolgen hat.

XMPP

RFC 6120 - "Extensible Messaging and Presence Protocol (XMPP): Core" (https://www.rfc-editor.org/rfc/rfc6120.txt)

13.7.1.2. Server Certificates

13.7.1.2.1. Rules

   In a PKIX certificate to be presented by an XMPP server (i.e., a
   "server certificate"), the certificate SHOULD include one or more
   XMPP addresses (i.e., domainparts) associated with XMPP services
   hosted at the server.

Es ist empfohlen einen oder mehrere Domainteile → 'janedoe@example.com' → 'example.com' im Zertifikat vorzuweisen.
Das wird in dNSName (OpenSSL: DNS) in der Extension 'SubjectAltName' sein (steht hier nicht, ergibt sich aus anderen RFC).

      Support for the SRV-ID identifier type [PKIX-SRV] is REQUIRED for
      XMPP client and server software implementations (for verification
      purposes XMPP client implementations need to support only the
      "_xmpp-client" service type, whereas XMPP server implementations
      need to support both the "_xmpp-client" and "_xmpp-server" service
      types).  Certification authorities that issue XMPP-specific
      certificates SHOULD support the SRV-ID identifier type.  XMPP
      service providers SHOULD include the SRV-ID identifier type in

Bei Nutzung von SRV-Records zur Auflösung des eigentlichen Host-Namens müssen diese im 'srv'-Feld in der Sektion 'SubjectAltName' im Zertifikat aufgeführt werden.
Gemeint ist hier nicht der Host in den der SRV-Record auflöst, sondern der SRV-Teil des Eintrags, also '_xmpp._tls.example.com'.
In der Praxis ignorieren viele Clients diese Regel allerdings, weil viele XMPP-Server mit kostenlosen Zertifikaten betrieben werden, die solche Zusätze nicht zulassen.

      Support for the XmppAddr identifier type (specified under
      Section 13.7.1.4) is encouraged in XMPP client and server software
      implementations for the sake of backward-compatibility, but is no
      longer encouraged in certificates issued by certification
      authorities or requested by XMPP service providers.

Man wird ermuntert eine 'XmppAddr'-Eintrag in 'SubjectAltName' anzugeben, aber das ist nicht mehr notwendig. Es geht hier vor allem um Rückwärtskompatibilität mit alter Software.

      DNS domain names in server certificates MAY contain the wildcard
      character '*' as the complete left-most label within the
      identifier.

Und letzten Endes wird die Nutzung von Wildcard-Zertifikaten explizit erlaubt.

Warum Reference-IDs keine Host-/ Domainnamen aus DNS-Einträgen nutzen dürfen

Bzw. die Reference-IDs/ die Domains gegen die das Zertifikat geprüft wird nur aus Daten die der Client selbst hat gebildet werden dürfen.

Die Antwort ist einfach und kurz, weil DNS (das klassische, nicht DNSSEC) unsicher ist und alles was aufgelöst wird potentiell gefälschte Einträge enthalten kann.
Alles was aus dem DNS kommt kann also nicht benutzt werden um festzustellen das man mit einer legitimen Gegenstelle spricht.

Zum besseren Verständnis einige Ausführungen…

srv dns resolution

Wie ersichtlich spricht der Client bei der Auflösung von '_xmpp._tls.example.com' nie direkt mit dem DNS-Server von 'example.com'.
Statt dessen in der Regel mit dem DNS-Server seines ISP. Der wiederum macht eine Menge Namensauflösungen um überhaupt erst einmal den DNS-Server von 'example.com' zu finden, von denen der Client gar nichts mitbekommt und letztendlich fragt er den DNS-Server von 'example.com' nach dem Namen der hinter '_xmpp._tls.example.com' steht und gibt die Antwort an den Client weiter.
In der Realität steht meist zwischen Client und dem ISP-DNS-Server noch ein caching-DNS-Server der aufgelöste Namen zwischenspeichert auf dem Heimrouter oder DNS-Server in Firmennetzwerken, und Firewalls die filtern, auch auf Provider-Seite können noch mehrere zwischengeschaltete Instanzen vorhanden sein.


Probleme ergeben sich nun:

  • wenn einer der Instanzen die an irgendeiner Auflösung beteiligt ist bösartig ist und falsch auflöst

    • DNS (das klassische) benutzt keine Zertifikate → Server-Identitäten lassen sich also nicht prüfen

  • auf dem Client ein bösartiger DNS-Server konfiguriert ist

  • irgendwo zwischen Client und irgendeinem DNS-Server ein Angreifer DNS-Antworten umschreibt

    • DNS (das klassische) ist nicht verschlüsselt und hat keine kryptografischen Prüfsummen → Antworten lassen sich also unentdeckt ändern

evil resolution

In obiger Grafik ist zu sehen was passiert wenn eine DNS-Instanz bösartig ist.

  • 1: Client fragt den bösartigen DNS-Server nach der Auflösung von '_xmpp._tls.example.com'

  • 2: Bösartiger DNS-Server löst falsch in 'xmpp5.evil.com' auf

  • 3-6: Auflösung des falschen Hosts xmpp5.evil.com in eine IP-Adresse

  • 7. Client baut TLS-Verbindung zu Server 'xmpp5.evil.com' auf

  • 8. Server sendet Client Zertifakt mit DNS-Name 'xmpp5.evil.com'

Wenn der Client das Ergebnis der Auflösung von '_xmpp._tls.example.com' in 'xmpp5.evil.com' als Referenz-ID akzeptieren würde, sprich das Zertifikat gegen diesen Namen geprüft würde, würde er an dieser Stelle die Verbindung zum falschen XMPP-Server herstellen und annehemn er sei mit dem zuständigen XMPP-Server verbunden.
Wenn hingegen nur - wie es der oben zitierte RFC vorsieht - die "origin" Domain und der SRV-Domain-Name ('_xmpp._tls.example.com') als Reference-ID akzeptiert wird, tritt das Problem nicht auf. Denn in diesem Fall würde der falsche XMPP-Server ein Zertifikat mit einem DNS-Eintrag 'xmpp5.evil.com' präsentieren, aber der Client würde es gegen 'example.com' (Origin-Domain aus der User-ID janedoe@example.com) und '_xmpp._tls.example.com' prüfen und keiner von beiden steht im Zertifikat. Damit würde die TLS-Verbindung von Seiten des Clients dann abgebrochen.

valid resolution

Oben stehend der Gut-Fall, wo alles stimmt.
Man beachte das die Daten im Zertifikat und in der Reference-ID-List übereinstimmen.

wrong dns name in cert

Oben stehend der Vollständigkeit halber ein Fall wo keine Boshaftigkeit im spiel ist, aber ein Konfigurationsfehler.
Das Zertifikat enthält als DNS-Eintrag den Hostnamen des Servers 'xmpp1.example.com', damit würde die Verbindung abgelehnt, da er nicht mit dem DNS-Eintrag in der Reference-ID-Liste übereinstimmt

Wie dieser Artikel eigentlich zustande gekommen ist

Eigentlich wollte ich "nur" meinen Prosody-Server (XMPP-Server/Jabber-Server) auf eine neue Maschine und in einen Container umziehen.
Um sicher zu gehen dass alles danach reibungslos funktionieren würde und ich die Konfiguration des Containers richtig hinbekommen habe, wollte ich eine Test-Instanz unter einem anderen Domain-Namen starten. Dafür brauchte ich natürlich (neben der Domain) auch ein Zertifikat.
Nach dem alles eingerichtet wurde verweigerte der Client (Conversations) die Zusammenarbeit mit der Meldung "Domain nicht überprüfbar" bzw. englisch "Domain not verifiable".
Was mich verwunderte, denn mein Zertifikat war auf 'xmpp.test.shellkraut.de' (ist nicht die echte Domain) ausgestellt, worauf der SRV-Record '_xmpp._tls.test.shellkraut.de' verwies und die JID (Jabber-ID) war auf 'someuser@test.shellkraut.de' gesetzt. Entsprechend sollte der Client ja nach '_xmpp._tls.test.shellkraut.de' in PTR suchen und der das dann richtig in 'xmpp.test.shellkraut.de' aufgelöst werden und dann in der Folge in eine IP-Adresse auflösen und nach der Verbindung entsprechende Zertifikat für 'xmpp.test.shellkraut.de' vorgewiesen bekommen.
Über die Fehlermeldung fand ich folgenden "Bug"-Report https://codeberg.org/iNPUTmice/Conversations/issues/50 in dem der Autor u.a. schrieb:

DNS (without DNSSEC) is not a trusted chain.
[…]
To derive the hostname from the domain. Finding the server on the network is independent of verifying the certificate.
[…]
Having the domain name in the certificate is the correct(tm) setup unless you have very very good reasons not to do this.

Das hat mich etwas verwundert, schließlich ist der FQDN des Hosts der den Dienst anbietet ja tatsächlich 'xmpp.test.shellkraut.de', nur in der JID (Jabber-ID) steht 'test.shellkraut.de', ich habe nicht verstanden warum es der Domainname in der JID sein sollte.
Dann begann die lange Reise durch das Internet und RFC :)