Zum Hauptinhalt springen

7. Key Exchange (Schlüsselaustausch)

7. Key Exchange (Schlüsselaustausch)​

Der Schlüsselaustausch (key exchange, kex) beginnt damit, dass jede Seite Namenslisten (name-lists) unterstützter Algorithmen sendet. Jede Seite hat in jeder Kategorie einen bevorzugten Algorithmus, und es wird angenommen, dass die meisten Implementierungen zu einem gegebenen Zeitpunkt denselben bevorzugten Algorithmus verwenden. Jede Seite KANN raten, welchen Algorithmus die andere Seite nutzt, und KANN gegebenenfalls ein anfängliches Schlüsselaustauschpaket gemäß dem Algorithmus senden.

Die Vermutung gilt als falsch, wenn:

  • der kex-Algorithmus und/oder der Host-Schlüssel-Algorithmus falsch geraten wurde (Server und Client haben unterschiedliche bevorzugte Algorithmen), oder

  • wenn einer der übrigen Algorithmen nicht vereinbart werden kann (das Verfahren ist unten in Abschnitt 7.1 definiert).

Andernfalls gilt die Vermutung als richtig, und das optimistisch gesendete Paket MUSS als erstes Schlüsselaustauschpaket verarbeitet werden.

War die Vermutung jedoch falsch und wurde von einer oder beiden Parteien optimistisch ein Paket gesendet, MÜSSEN solche Pakete ignoriert werden (selbst wenn der Fehler in der Vermutung den Inhalt der anfänglichen Pakete nicht beeinflussen würde), und die zuständige Seite MUSS das korrekte anfängliche Paket senden.

Eine Schlüsselaustauschmethode verwendet explizite Serverauthentifizierung (explicit server authentication), wenn die Schlüsselaustauschnachrichten eine Signatur oder einen anderen Nachweis der Echtheit des Servers enthalten. Eine Schlüsselaustauschmethode verwendet implizite Serverauthentifizierung (implicit server authentication), wenn der Server zum Nachweis seiner Echtheit außerdem zeigen muss, dass er das gemeinsame Geheimnis K kennt, indem er eine Nachricht und einen zugehörigen MAC sendet, den der Client verifizieren kann.

Die in diesem Dokument definierte Schlüsselaustauschmethode verwendet explizite Serverauthentifizierung. Schlüsselaustauschmethoden mit impliziter Serverauthentifizierung KÖNNEN jedoch mit diesem Protokoll verwendet werden. Nach einem Schlüsselaustausch mit impliziter Serverauthentifizierung MUSS der Client auf eine Antwort auf seine Dienstanforderungsnachricht warten, bevor er weitere Daten sendet.

7.1. Algorithm Negotiation (Algorithmusauswahl)​

Der Schlüsselaustausch beginnt damit, dass jede Seite folgendes Paket sendet:

      byte         SSH_MSG_KEXINIT
byte[16] cookie (Zufallsbytes)
name-list kex_algorithms
name-list server_host_key_algorithms
name-list encryption_algorithms_client_to_server
name-list encryption_algorithms_server_to_client
name-list mac_algorithms_client_to_server
name-list mac_algorithms_server_to_client
name-list compression_algorithms_client_to_server
name-list compression_algorithms_server_to_client
name-list languages_client_to_server
name-list languages_server_to_client
boolean first_kex_packet_follows
uint32 0 (für künftige Erweiterungen reserviert)

Jede der Algorithmus-Namenslisten MUSS eine kommagetrennte Liste von Algorithmusnamen sein (siehe Algorithm Naming in [SSH-ARCH] und weitere Informationen in [SSH-NUMBERS]). Jeder unterstützte (zulässige) Algorithmus MUSS in Reihenfolge der Präferenz, vom höchsten zum niedrigsten, aufgeführt sein.

Der erste Algorithmus in jeder Namensliste MUSS der bevorzugte (geratene) Algorithmus sein. Jede Namensliste MUSS mindestens einen Algorithmusnamen enthalten.

      cookie
         Das 'cookie' MUSS ein vom Sender erzeugter Zufallswert sein.
         Sein Zweck ist es, beiden Seiten unmöglich zu machen, die
         Schlüssel und die Sitzungskennung vollständig zu bestimmen.
      kex_algorithms
         Schlüsselaustauschalgorithmen wurden oben definiert. Der erste
         Algorithmus MUSS der bevorzugte (geratene) Algorithmus sein.
         Treffen beide Seiten dieselbe Vermutung, MUSS dieser Algorithmus
         verwendet werden. Andernfalls MUSS der folgende Algorithmus
         verwendet werden, um eine Schlüsselaustauschmethode zu wählen:
         Iteriere über die kex-Algorithmen des Clients, jeweils einen.
         Wähle den ersten Algorithmus, der folgende Bedingungen erfüllt:
         +  der Server unterstützt den Algorithmus ebenfalls,
         +  erfordert der Algorithmus einen verschlüsselungsfähigen
            Host-Schlüssel, gibt es auf der server_host_key_algorithms-
            Liste des Servers einen verschlüsselungsfähigen Algorithmus,
            den auch der Client unterstützt, und
         +  erfordert der Algorithmus einen signaturfähigen Host-Schlüssel,
            gibt es auf der server_host_key_algorithms-Liste des Servers
            einen signaturfähigen Algorithmus, den auch der Client
            unterstützt.
      Kann kein Algorithmus gefunden werden, der all diese Bedingungen
      erfüllt, schlägt die Verbindung fehl, und beide Seiten MÜSSEN
      die Verbindung trennen.
      server_host_key_algorithms
         Eine Namensliste der Algorithmen, die für den Server-Host-
         Schlüssel unterstützt werden. Der Server listet Algorithmen,
         für die er Host-Schlüssel hat; der Client listet Algorithmen,
         die er akzeptieren will. Es KANN mehrere Host-Schlüssel für
         einen Host geben, möglicherweise mit unterschiedlichen
         Algorithmen.
         Einige Host-Schlüssel unterstützen möglicherweise weder
         Signaturen noch Verschlüsselung (dies kann am Algorithmus
         abgelesen werden), daher sind nicht alle Host-Schlüssel für
         alle Schlüsselaustauschmethoden gültig.
         Die Algorithmuswahl hängt davon ab, ob der gewählte
         Schlüsselaustauschalgorithmus einen signatur- oder einen
         verschlüsselungsfähigen Host-Schlüssel erfordert. Es MUSS
         aus dem Namen des Public-Key-Algorithmus bestimmbar sein.
         Der erste Algorithmus auf der Namensliste des Clients, der
         die Anforderungen erfüllt und vom Server unterstützt wird,
         MUSS gewählt werden. Gibt es keinen solchen Algorithmus,
         MÜSSEN beide Seiten die Verbindung trennen.
      encryption_algorithms
         Eine Namensliste akzeptabler symmetrischer Verschlüsselungs-
         algorithmen (auch Chiffren genannt) in Präferenzreihenfolge.
         Der gewählte Verschlüsselungsalgorithmus für jede Richtung MUSS
         der erste Algorithmus auf der Namensliste des Clients sein,
         der auch auf der Namensliste des Servers steht. Gibt es keinen
         solchen Algorithmus, MÜSSEN beide Seiten die Verbindung trennen.
         Beachten Sie, dass "none" ausdrücklich aufgeführt sein muss,
         wenn es akzeptabel sein soll. Die definierten Algorithmusnamen
         sind in Abschnitt 6.3 aufgeführt.
      mac_algorithms
         Eine Namensliste akzeptabler MAC-Algorithmen in Präferenz-
         reihenfolge. Der gewählte MAC-Algorithmus MUSS der erste
         Algorithmus auf der Namensliste des Clients sein, der auch
         auf der Namensliste des Servers steht. Gibt es keinen solchen
         Algorithmus, MÜSSEN beide Seiten die Verbindung trennen.
         Beachten Sie, dass "none" ausdrücklich aufgeführt sein muss,
         wenn es akzeptabel sein soll. Die MAC-Algorithmusnamen sind in
         Abschnitt 6.4 aufgeführt.
      compression_algorithms
         Eine Namensliste akzeptabler Kompressionsalgorithmen in
         Präferenzreihenfolge. Der gewählte Kompressionsalgorithmus MUSS
         der erste Algorithmus auf der Namensliste des Clients sein, der
         auch auf der Namensliste des Servers steht. Gibt es keinen
         solchen Algorithmus, MÜSSEN beide Seiten die Verbindung trennen.
         Beachten Sie, dass "none" ausdrücklich aufgeführt sein muss,
         wenn es akzeptabel sein soll. Die Kompressionsalgorithmusnamen
         sind in Abschnitt 6.2 aufgeführt.
      languages
         Dies ist eine Namensliste von Sprach-Tags in Präferenzreihenfolge
         [RFC3066]. Beide Parteien KÖNNEN diese Namensliste ignorieren.
         Gibt es keine Sprachpräferenzen, SOLLTE diese Namensliste leer
         sein, wie in Abschnitt 5 von [SSH-ARCH] definiert. Sprach-Tags
         SOLLTEN nicht vorhanden sein, es sei denn, der sendenden Partei
         ist bekannt, dass sie benötigt werden.
      first_kex_packet_follows
         Gibt an, ob ein geratenes Schlüsselaustauschpaket folgt. Wird
         ein geratenes Paket gesendet, MUSS dieses Feld TRUE sein. Wird
         kein geratenes Paket gesendet, MUSS es FALSE sein.
         Nach Empfang des SSH_MSG_KEXINIT-Pakets der anderen Seite weiß
         jede Partei, ob ihre Vermutung richtig war. War die Vermutung
         der anderen Partei falsch und war dieses Feld TRUE, MUSS das
         nächste Paket stillschweigend ignoriert werden, und beide
         Seiten MÜSSEN dann gemäß der ausgehandelten Schlüsselaustausch-
         methode handeln. War die Vermutung richtig, MUSS der Schlüssel-
         austausch mit dem geratenen Paket fortgesetzt werden.

Nach dem SSH_MSG_KEXINIT-Nachrichtenaustausch wird der Schlüsselaustauschalgorithmus ausgeführt. Er kann mehrere Paketaustausche umfassen, wie von der Schlüsselaustauschmethode spezifiziert.

Hat eine Partei eine SSH_MSG_KEXINIT-Nachricht für Schlüsselaustausch oder Neuaustausch gesendet, DARF sie bis zum Senden einer SSH_MSG_NEWKEYS-Nachricht (Abschnitt 7.3) KEINE anderen Nachrichten senden als:

  • generische Nachrichten der Transportschicht (1 bis 19) (SSH_MSG_SERVICE_REQUEST und SSH_MSG_SERVICE_ACCEPT DÜRFEN jedoch NICHT gesendet werden);

  • Nachrichten zur Algorithmusverhandlung (20 bis 29) (weitere SSH_MSG_KEXINIT-Nachrichten DÜRFEN jedoch NICHT gesendet werden);

  • spezifische Nachrichten der Schlüsselaustauschmethode (30 bis 49).

Die Bestimmungen von Abschnitt 11 gelten für nicht erkannte Nachrichten.

Beachten Sie jedoch, dass während eines Schlüsselneuaustauschs nach dem Senden einer SSH_MSG_KEXINIT-Nachricht jede Partei darauf vorbereitet sein MUSS, eine beliebige Anzahl von Nachrichten zu verarbeiten, die unter Umständen noch unterwegs sind, bevor eine SSH_MSG_KEXINIT-Nachricht der anderen Partei empfangen wird.

7.2. Output from Key Exchange (Ergebnis des Schlüsselaustauschs)​

Der Schlüsselaustausch liefert zwei Werte: ein gemeinsames Geheimnis K und einen Austausch-Hash H. Verschlüsselungs- und Authentifizierungsschlüssel werden daraus abgeleitet. Der Austausch-Hash H aus dem ersten Schlüsselaustausch dient zusätzlich als Sitzungskennung (session identifier), die diese Verbindung eindeutig identifiziert. Sie wird von Authentifizierungsmethoden als Teil der Daten verwendet, die als Nachweis des Besitzes eines privaten Schlüssels signiert werden. Einmal berechnet, ändert sich die Sitzungskennung nicht, auch wenn Schlüssel später neu ausgetauscht werden.

Jede Schlüsselaustauschmethode spezifiziert eine Hash-Funktion, die im Schlüsselaustausch verwendet wird. Derselbe Hash-Algorithmus MUSS bei der Schlüsselableitung verwendet werden. Hier nennen wir ihn HASH.

Verschlüsselungsschlüssel MÜSSEN als HASH eines bekannten Werts und K wie folgt berechnet werden:

  • Initialisierungsvektor (IV) Client zu Server: HASH(K || H || "A" || session_id) (K ist als mpint kodiert, "A" als Byte und session_id als Rohdaten. "A" bedeutet das einzelne Zeichen A, ASCII 65).

  • Initialisierungsvektor Server zu Client: HASH(K || H || "B" || session_id)

  • Verschlüsselungsschlüssel Client zu Server: HASH(K || H || "C" || session_id)

  • Verschlüsselungsschlüssel Server zu Client: HASH(K || H || "D" || session_id)

  • Integritätsschlüssel Client zu Server: HASH(K || H || "E" || session_id)

  • Integritätsschlüssel Server zu Client: HASH(K || H || "F" || session_id)

Schlüsseldaten MÜSSEN vom Beginn der Hash-Ausgabe genommen werden. Es werden so viele Bytes vom Beginn des Hashwerts benötigt wie nötig. Ist die benötigte Schlüssellänge länger als die Ausgabe von HASH, wird der Schlüssel erweitert, indem HASH über die Verkettung von K und H und den bisherigen gesamten Schlüssel berechnet und die resultierenden Bytes (so viele wie HASH erzeugt) an den Schlüssel angehängt werden. Dies wird wiederholt, bis genug Schlüsselmaterial vorhanden ist; der Schlüssel wird vom Beginn dieses Werts genommen. Mit anderen Worten:

      K1 = HASH(K || H || X || session_id)   (X ist z. B. "A")
K2 = HASH(K || H || K1)
K3 = HASH(K || H || K1 || K2)
...
key = K1 || K2 || K3 || ...

Dieser Prozess verliert Entropie, wenn die Entropiemenge in K größer ist als die interne Zustandsgröße von HASH.

7.3. Taking Keys Into Use (Inbetriebnahme der Schlüssel)​

Der Schlüsselaustausch endet damit, dass jede Seite eine SSH_MSG_NEWKEYS-Nachricht sendet. Diese Nachricht wird mit den alten Schlüsseln und Algorithmen gesendet. Alle nach dieser Nachricht gesendeten Nachrichten MÜSSEN die neuen Schlüssel und Algorithmen verwenden.

Wird diese Nachricht empfangen, MÜSSEN die neuen Schlüssel und Algorithmen zum Empfangen verwendet werden.

Zweck dieser Nachricht ist sicherzustellen, dass eine Partei bei Problemen mit dem Schlüsselaustausch mit einer SSH_MSG_DISCONNECT-Nachricht antworten kann, die die andere Partei versteht.

      byte      SSH_MSG_NEWKEYS