Zum Hauptinhalt springen

8. Identifier Validation Challenges (Identifikator-Validierungsherausforderungen)

Es gibt nur wenige Identifikatortypen in der Welt, für die es standardisierte Mechanismen gibt, um den Besitz eines bestimmten Identifikators nachzuweisen. In allen praktischen Fällen verlassen sich CAs auf verschiedene Mittel, um zu testen, ob eine Entität, die ein Zertifikat für einen bestimmten Identifikator beantragt, diesen Identifikator tatsächlich kontrolliert.

Herausforderungen geben dem Server die Gewissheit, dass der Kontoinhaber auch die Entität ist, die den Identifikator kontrolliert. Für jeden Herausforderungstyp müssen die folgenden Bedingungen erfüllt sein: Damit eine Entität eine Herausforderung erfolgreich abschließt, muss die Entität gleichzeitig:

  • den privaten Schlüssel des Kontoschlüsselpaars besitzen, das zur Beantwortung der Herausforderung verwendet wird, und
  • den betreffenden Identifikator kontrollieren.

Abschnitt 10 dokumentiert, wie die in diesem Dokument definierten Herausforderungen diese Anforderungen erfüllen. Neue Herausforderungen müssen dokumentieren, wie sie diese erfüllen.

ACME verwendet ein erweiterbares Herausforderungs-/Antwort-Framework für die Identifikatorvalidierung. Der Server präsentiert dem Client eine Reihe von Herausforderungen (als Objekte im „challenges"-Array) im Autorisierungsobjekt, das an den Client gesendet wird, und der Client antwortet, indem er ein Antwortobjekt in einer POST-Anforderung an die Herausforderungs-URL sendet.

Dieser Abschnitt beschreibt eine Reihe von anfänglichen Herausforderungstypen. Die Definition eines Herausforderungstyps umfasst:

  1. Den Inhalt des Herausforderungsobjekts
  2. Den Inhalt des Antwortobjekts
  3. Wie der Server die Herausforderung und die Antwort verwendet, um die Kontrolle über den Identifikator zu validieren

Herausforderungsobjekte enthalten alle die folgenden Basisfelder:

type (erforderlich, Zeichenkette): Der im Objekt kodierte Herausforderungstyp.

url (erforderlich, Zeichenkette): Die URL, an die eine Antwort gesendet werden kann.

status (erforderlich, Zeichenkette): Der Status dieser Herausforderung. Mögliche Werte sind „pending", „processing", „valid" und „invalid" (siehe Abschnitt 7.1.6).

validated (optional, Zeichenkette): Der Zeitpunkt, zu dem der Server diese Herausforderung validiert hat, kodiert im in [RFC3339] angegebenen Format. Dieses Feld ist ERFORDERLICH (REQUIRED), wenn das „status"-Feld „valid" ist.

error (optional, Objekt): Der Fehler, der beim Validieren der Herausforderung durch den Server aufgetreten ist, falls vorhanden, strukturiert als Problemdokument [RFC7807]. Mehrere Fehler können mit Teilproblemen (Abschnitt 6.7.1) angegeben werden. Der Status eines Herausforderungsobjekts mit Fehlern MUSS (MUST) „invalid" sein.

Alle anderen Felder werden durch den Herausforderungstyp angegeben. Wenn der Server den „status" einer Herausforderung auf „invalid" setzt, SOLLTE (SHOULD) er auch das „error"-Feld einschließen, um dem Client bei der Diagnose des Grundes für das Scheitern der Herausforderung zu helfen.

Verschiedene Herausforderungen ermöglichen es dem Server, Nachweise über verschiedene Aspekte der Kontrolle über einen Identifikator zu erhalten. Bei einigen Herausforderungen, wie HTTP und DNS, weist der Client direkt seine Fähigkeit nach, bestimmte Operationen im Zusammenhang mit dem Identifikator durchzuführen. Die Wahl, welche Herausforderungen dem Client unter welchen Umständen angeboten werden, ist eine Frage der Serverrichtlinie.

Die in diesem Abschnitt beschriebenen Identifikator-Validierungsherausforderungen beziehen sich alle auf die Domainvalidierung. Wenn ACME in Zukunft erweitert wird, um andere Identifikatortypen zu unterstützen, werden neue Herausforderungstypen benötigt, und diese müssen angeben, für welche Identifikatortypen sie gelten.

8.1. Key Authorizations (Schlüsselautorisierungen)

Alle in diesem Dokument definierten Herausforderungen verwenden Schlüsselautorisierungszeichenketten. Eine Schlüsselautorisierung ist eine Zeichenkette, die das Token der Herausforderung mit einem Schlüssel-Fingerabdruck verbindet, getrennt durch ein „."-Zeichen:

keyAuthorization = token || '.' || base64url(Thumbprint(accountKey))

Der „Thumbprint"-Schritt stellt die in [RFC7638] angegebene Berechnung dar, unter Verwendung des SHA-256-Digests [FIPS180-4]. Wie in [RFC7518] beschrieben, MÜSSEN (MUST) alle führenden Null-Oktette in JWK-Objektfeldern vor der Berechnung entfernt werden.

Wie in den einzelnen Herausforderungen unten angegeben, ist das Token einer Herausforderung eine Zeichenkette, die ausschließlich aus Zeichen des URL-sicheren base64-Alphabets besteht. Der „||"-Operator stellt die Verkettung von Zeichenketten dar.

8.2. Retrying Challenges (Wiederholen von Herausforderungen)

ACME-Herausforderungen erfordern in der Regel, dass der Client eine netzwerkzugängliche Ressource einrichtet, die der Server abfragen kann, um zu überprüfen, ob der Client den Identifikator kontrolliert. In der Praxis ist es nicht ungewöhnlich, dass die Abfrage des Servers beim Einrichten der Ressource fehlschlägt, z. B. weil Informationen sich in einem Cluster verbreiten oder Firewall-Regeln noch nicht in Kraft sind.

Clients SOLLTEN NICHT (SHOULD NOT) auf Herausforderungen antworten, bis sie glauben, dass die Abfrage des Servers erfolgreich sein wird. Wenn die anfängliche Validierungsabfrage des Servers fehlschlägt, SOLLTE (SHOULD) der Server die Abfrage nach einer Weile wiederholen, um Verzögerungen beim Einrichten der Antwort (wie DNS-Einträge oder HTTP-Ressourcen) zu berücksichtigen. Der genaue Wiederholungsplan liegt im Ermessen des Servers, aber Serverbetreiber sollten die Betriebsszenarien im Hinterkopf behalten, die der Plan zu berücksichtigen versucht. Da Wiederholungen darauf abzielen, Probleme wie Ausbreitungsverzögerungen in HTTP- oder DNS-Konfigurationen zu lösen, sollte es in der Regel keinen Grund geben, öfter als alle 5 oder 10 Sekunden zu wiederholen. Während der Server noch versucht, bleibt der Status der Herausforderung „processing"; erst nachdem der Server aufgegeben hat, wird sie als „invalid" markiert.

Der Server MUSS (MUST) dem Client Informationen über seinen Wiederholungsstatus über das „error"-Feld in der Herausforderung und das Retry-After-HTTP-Headerfeld in Antworten auf Herausforderungsressourcenanforderungen bereitstellen. Der Server MUSS (MUST) nach jeder fehlgeschlagenen Validierungsabfrage einen Eintrag zum „error"-Feld in der Herausforderung hinzufügen. Der Server SOLLTE (SHOULD) das Retry-After-Headerfeld auf einen Zeitpunkt nach der nächsten Validierungsabfrage des Servers setzen, da sich der Status der Herausforderung vor diesem Zeitpunkt nicht ändern wird.

Ein Client kann explizit eine Wiederholung anfordern, indem er die Antwort auf die Herausforderung in einer neuen POST-Anforderung erneut sendet (mit einer neuen Nonce usw.). Dies ermöglicht es dem Client, eine Wiederholung anzufordern, wenn sich der Zustand geändert hat (z. B. nach der Aktualisierung von Firewall-Regeln). Der Server SOLLTE (SHOULD) die Anforderung sofort wiederholen, wenn er eine solche POST-Anforderung erhält. Um Denial-of-Service-Angriffe durch clientinitiierte Wiederholungen zu vermeiden, SOLLTE (SHOULD) der Server solche Anforderungen ratenbegrenzen.

8.3. HTTP Challenge (HTTP-Herausforderung)

Bei der HTTP-Validierung weist der Client in einer ACME-Transaktion seine Kontrolle über einen Domainnamen nach, indem er beweist, dass er eine HTTP-Ressource auf einem unter diesem Domainnamen zugänglichen Server konfigurieren kann. Der ACME-Server fordert den Client auf, eine Datei unter einem bestimmten Pfad zu konfigurieren, mit einer bestimmten Zeichenkette als Inhalt.

Da ein Domainname möglicherweise mehrere IPv4- und IPv6-Adressen auflöst, verbindet sich der Server nach eigenem Ermessen mit mindestens einem der in den DNS-A- und AAAA-Einträgen gefundenen Hosts. Da viele Webserver den Standard-HTTPS-Virtual-Host auf subtile und nicht intuitive Weise bestimmten Mietern mit niedrigen Berechtigungen zuweisen, MUSS die Herausforderung über HTTP und nicht über HTTPS abgeschlossen werden.

type (erforderlich, Zeichenkette): Die Zeichenkette „http-01".

token (erforderlich, Zeichenkette): Ein zufälliger Wert, der die Herausforderung eindeutig identifiziert. Dieser Wert MUSS (MUST) mindestens 128 Bit Entropie haben. Er DARF NICHT (MUST NOT) Zeichen außerhalb des base64url-Alphabets enthalten und DARF NICHT (MUST NOT) base64-Füllzeichen („=") enthalten. Weitere Informationen zu Zufälligkeitsanforderungen finden Sie in [RFC4086].

{
"type": "http-01",
"url": "https://example.com/acme/chall/prV_B7yEyA4",
"status": "pending",
"token": "LoqXcYV8q5ONbJQxbmR7SCTNo3tiAXDfowyjxAjEuX0"
}

Der Client schließt diese Herausforderung ab, indem er eine Schlüsselautorisierung aus dem in der Herausforderung bereitgestellten „token"-Wert und dem Kontoschlüssel des Clients konstruiert. Der Client konfiguriert dann die Schlüsselautorisierung als Ressource auf dem HTTP-Server für den betreffenden Domainnamen.

Der Pfad, unter dem die Ressource konfiguriert wird, besteht aus dem festen Präfix „/.well-known/acme-challenge/" gefolgt vom „token"-Wert in der Herausforderung. Der Wert der Ressource MUSS (MUST) die ASCII-Darstellung der Schlüsselautorisierung sein.

GET /.well-known/acme-challenge/LoqXcYV8...jxAjEuX0
Host: example.org

HTTP/1.1 200 OK
Content-Type: application/octet-stream

LoqXcYV8...jxAjEuX0.9jg46WB3...fm21mqTI

(Im obigen Beispiel zeigt „..." an, dass das Token und der JWK-Fingerabdruck in der Schlüsselautorisierung abgeschnitten wurden, um auf die Seite zu passen.)

Der Client antwortet mit einem leeren Objekt ({}), um zu bestätigen, dass der Server die Herausforderung validieren kann.

POST /acme/chall/prV_B7yEyA4
Host: example.com
Content-Type: application/jose+json

{
"protected": base64url({
"alg": "ES256",
"kid": "https://example.com/acme/acct/evOfKhNU60wg",
"nonce": "UQI1PoRi5OuXzxuX7V7wL0",
"url": "https://example.com/acme/chall/prV_B7yEyA4"
}),
"payload": base64url({}),
"signature": "Q1bURgJoEslbD1c5...3pYdSMLio57mQNN4"
}

Beim Empfang der Antwort konstruiert und speichert der Server die Schlüsselautorisierung aus dem Herausforderungs-„token"-Wert und dem aktuellen Kontoschlüssel des Clients.

Anhand des Herausforderungs-/Antwortpaares validiert der Server die Kontrolle des Clients über den Domainnamen, indem er überprüft, ob die Ressource wie erwartet konfiguriert ist.

  1. Konstruieren der URL durch Ausfüllen der URL-Vorlage [RFC6570] „http://{domain}/.well-known/acme-challenge/{token}", wobei:

    • das domain-Feld auf den zu validierenden Domainnamen gesetzt wird; und
    • das token-Feld auf das Token in der Herausforderung gesetzt wird.
  2. Überprüfen, ob die resultierende URL wohlgeformt ist.

  3. Dereferenzieren der URL mit einer HTTP-GET-Anforderung. Diese Anforderung MUSS (MUST) an TCP-Port 80 auf dem HTTP-Server gesendet werden.

  4. Überprüfen, ob der Körper der Antwort eine wohlgeformte Schlüsselautorisierung ist. Der Server SOLLTE (SHOULD) Leerzeichen am Ende des Körpers ignorieren.

  5. Überprüfen, ob die vom HTTP-Server bereitgestellte Schlüsselautorisierung mit der vom Server gespeicherten Schlüsselautorisierung übereinstimmt.

Der Server SOLLTE (SHOULD) beim Dereferenzieren der URL Weiterleitungen folgen. Beispielsweise kann ein Client Weiterleitungen verwenden, damit die Antwort von einem zentralisierten Zertifikatsverwaltungsserver bereitgestellt werden kann. Sicherheitsüberlegungen im Zusammenhang mit Weiterleitungen finden Sie in Abschnitt 10.2.

Wenn alle oben genannten Validierungen erfolgreich sind, ist die Validierung erfolgreich. Wenn die Anforderung fehlschlägt oder der Körper diese Prüfungen nicht besteht, schlägt die Validierung fehl.

Clients SOLLTEN (SHOULD) die für diese Herausforderung konfigurierten Ressourcen nach Abschluss der Herausforderung entfernen, d. h. sobald der Wert des „status"-Felds der Herausforderung „valid" oder „invalid" ist.

Beachten Sie, dass das Token sowohl in der vom ACME-Server gesendeten Anforderung als auch in der Schlüsselautorisierung in der Antwort erscheint, sodass es möglich ist, Clients zu erstellen, die das Token von der Anforderung in die Antwort kopieren. Clients SOLLTEN dieses Verhalten vermeiden, da es zu Cross-Site-Scripting-Schwachstellen führen kann; stattdessen SOLLTEN Clients eine explizite Konfiguration auf Basis jeder Herausforderung vornehmen. Clients, die das Token tatsächlich von der Anforderung in die Antwort kopieren, MÜSSEN (MUST) überprüfen, ob das Token in der Anforderung der oben genannten Token-Syntax entspricht (z. B. enthält es nur Zeichen aus dem base64url-Alphabet).

8.4. DNS Challenge (DNS-Herausforderung)

Wenn der zu validierende Identifikator ein Domainname ist, kann der Client seine Kontrolle über diesen Domainnamen nachweisen, indem er einen TXT-Ressourceneintrag mit einem angegebenen Wert für einen bestimmten Validierungsdomainnamen konfiguriert.

type (erforderlich, Zeichenkette): Die Zeichenkette „dns-01".

token (erforderlich, Zeichenkette): Ein zufälliger Wert, der die Herausforderung eindeutig identifiziert. Dieser Wert MUSS (MUST) mindestens 128 Bit Entropie haben. Er DARF NICHT (MUST NOT) Zeichen außerhalb des base64url-Alphabets enthalten, einschließlich Füllzeichen („="). Weitere Informationen zu Zufälligkeitsanforderungen finden Sie in [RFC4086].

{
"type": "dns-01",
"url": "https://example.com/acme/chall/Rg5dV14Gh1Q",
"status": "pending",
"token": "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
}

Der Client schließt diese Herausforderung ab, indem er eine Schlüsselautorisierung aus dem in der Herausforderung bereitgestellten „token"-Wert und dem Kontoschlüssel des Clients konstruiert. Der Client berechnet dann den SHA-256-Digest [FIPS180-4] der Schlüsselautorisierung.

Der in DNS konfigurierte Eintrag enthält die base64url-Kodierung dieses Digests. Der Client konstruiert den Validierungsdomainnamen, indem er dem zu validierenden Domainnamen das Label „_acme-challenge" voranstellt, und konfiguriert dann einen TXT-Eintrag mit dem Digest-Wert unter diesem Namen. Wenn der zu validierende Domainname beispielsweise „www.example.org" ist, konfiguriert der Client den folgenden DNS-Eintrag:

_acme-challenge.www.example.org. 300 IN TXT "gfj9Xq...Rg85nM"

Der Client antwortet mit einem leeren Objekt ({}), um zu bestätigen, dass der Server die Herausforderung validieren kann.

POST /acme/chall/Rg5dV14Gh1Q
Host: example.com
Content-Type: application/jose+json

{
"protected": base64url({
"alg": "ES256",
"kid": "https://example.com/acme/acct/evOfKhNU60wg",
"nonce": "SS2sSl1PtspvFZ08kNtzKd",
"url": "https://example.com/acme/chall/Rg5dV14Gh1Q"
}),
"payload": base64url({}),
"signature": "Q1bURgJoEslbD1c5...3pYdSMLio57mQNN4"
}

Beim Empfang der Antwort konstruiert und speichert der Server die Schlüsselautorisierung aus dem Herausforderungs-„token"-Wert und dem aktuellen Kontoschlüssel des Clients.

Um die DNS-Herausforderung zu validieren, führt der Server die folgenden Schritte aus:

  1. Berechnen des SHA-256-Digests [FIPS180-4] der gespeicherten Schlüsselautorisierung

  2. Abfragen der TXT-Einträge für den Validierungsdomainnamen

  3. Überprüfen, ob der Inhalt eines der TXT-Einträge mit dem Digest-Wert übereinstimmt

Wenn alle oben genannten Validierungen erfolgreich sind, ist die Validierung erfolgreich. Wenn keine DNS-Einträge gefunden werden oder die DNS-Einträge und die Antwortnutzlast diese Prüfungen nicht bestehen, schlägt die Validierung fehl.

Clients SOLLTEN (SHOULD) die für diese Herausforderung konfigurierten Ressourceneinträge nach Abschluss der Herausforderung entfernen, d. h. sobald der Wert des „status"-Felds der Herausforderung „valid" oder „invalid" ist.