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