Date de publication du RFC : Mars 2018
Auteur(s) du RFC : D. Bider (Bitvise Limited)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF curdle
Première rédaction de cet article le 21 mars 2018
Dernière mise à jour le 28 mars 2018
Le protocole SSH n'avait pas de mécanisme propre pour négocier des extensions au protocole de base (comme celle du RFC 4335). En outre, une partie de la négociation, par exemple des algorithmes cryptographiques, se déroulait avant le début du chiffrement et n'était donc pas protégée. Ce nouveau RFC ajoute à SSH un mécanisme pour négocier les extensions après l'échange de clés et le début de la communication sécurisée, une fois que tout est confidentiel.
Un mécanisme de négociation pour un protocole cryptographique est toujours délicat (comme TLS s'en est aperçu à plusieurs reprises). Si on n'en a pas, le client et le serveur perdent beaucoup de temps à faire des essais/erreurs « tiens, il vient de déconnecter brusquement, c'est peut-être qu'il n'aime pas SHA-512, réessayons avec SHA-1 ». Et ces deux mécanismes (négociation explicite et essai/erreur) ouvrent une nouvelle voie d'attaque, celle des attaques par repli, où l'Homme du Milieu va essayer de forcer les deux parties à utiliser des algorithmes de qualité inférieure. (La seule protection serait de ne pas discuter, de choisir des algorithmes forts et de refuser tout repli. En sécurité, ça peut aider d'être obtus.)
Notez aussi que la méthode essais/erreurs a un danger spécifique, car bien des machines SSH mettent en œuvre des mécanismes de limitation du trafic, voire de mise en liste noire, si la machine en face fait trop d'essais, ceci afin d'empêcher des attaques par force brute. D'où l'intérêt d'un vrai mécanisme de négociation (qui peut en outre permettre de détecter certaines manipulations par l'Homme du Milieu).
Vue par tshark, voici
le début d'une négociation SSH, le message
SSH_MSG_KEXINIT
, normalisé dans le RFC 4253, section 7.1 :
SSH Protocol SSH Version 2 Packet Length: 1332 Padding Length: 5 Key Exchange Message Code: Key Exchange Init (20) Algorithms Cookie: 139228cb5cfbf6c97d6b74f6ae99453d kex_algorithms length: 196 kex_algorithms string: curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,ext-info-c server_host_key_algorithms length: 290 server_host_key_algorithms string [truncated]: ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ecdsa-s encryption_algorithms_client_to_server length: 150 encryption_algorithms_client_to_server string: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc encryption_algorithms_server_to_client length: 150 encryption_algorithms_server_to_client string: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc mac_algorithms_client_to_server length: 213 mac_algorithms_client_to_server string [truncated]: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-2 mac_algorithms_server_to_client length: 213 mac_algorithms_server_to_client string [truncated]: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-2 compression_algorithms_client_to_server length: 26 compression_algorithms_client_to_server string: none,zlib@openssh.com,zlib compression_algorithms_server_to_client length: 26 compression_algorithms_server_to_client string: none,zlib@openssh.com,zlib languages_client_to_server length: 0 languages_client_to_server string: [Empty] languages_server_to_client length: 0 languages_server_to_client string: [Empty] KEX First Packet Follows: 0 Reserved: 00000000 Padding String: 0000000000
Le message était en clair (c'est pour cela que tshark a pu le décoder). L'autre machine envoie un message équivalent. Suite à cet échange, les deux machines sauront quels algorithmes sont disponibles.
Notre RFC 8308 (section 2.1) ajoute à ce message le nouveau
mécanisme d'extension. Pour préserver la compatibilité avec les
anciennes mises en œuvre de SSH, et comme il n'y a pas de place
« propre » disponible dans le message, le nouveau mécanisme se
place dans la liste des algorithmes cryptographiques (champ
kex_algorithms
, celui qui commence par
curve25519-sha256@libssh.org,ecdh-sha2-nistp256…
). On
ajoute à cette liste ext-info-c
si on est
client et ext-info-s
si on est serveur. (Le
nom est différent dans chaque direction, pour éviter que les deux
parties ne se disent « cool, cet algorithme est commun,
utilisons-le ».) Vous
pouvez donc savoir si votre SSH gère le nouveau mécanisme en
capturant ce premier paquet SSH et en examinant la liste des
algorithmes d'échange de clé. (C'était le cas ici, avec
OpenSSH 7.2. Vous l'aviez repéré ?)
Une fois qu'on a proposé à son pair d'utiliser le nouveau
mécanisme de ce RFC 8308, on peut s'attendre, si le pair
est d'accord, à recevoir un message SSH d'un nouveau type,
SSH_MSG_EXT_INFO
, qui sera, lui, chiffré. Il contient la liste des
extensions gérées avec ce mécanisme. Notez qu'il peut être envoyé
plusieurs fois, par exemple avant et après l'authentification du
client, pour le cas d'un serveur timide qui ne voulait pas révéler
sa liste d'extensions avant l'authentification. Ce nouveau type de
message figure désormais dans le
registre des types de message, avec le numéro 7.
La section 3 définit les quatre extensions actuelles (un registre accueillera les extensions futures) :
server-sig-algs
donne la
liste des algorithmes de signature acceptés
par le serveur.delay-compression
indique les
algorithmes de compression acceptés. Il y
en a deux, un du client vers le serveur et un en sens
inverse. Ils étaient déjà indiqués dans le message
SSH_MSG_KEXINIT
, dans les champs
compression_algorithms_client_to_server
et
compression_algorithms_server_to_client
mais, cette fois, ils sont transmis dans un canal sécurisé
(confidentiel et authentifié).no-flow-control
, dont le nom indique
bien la fonction.elevation
sert aux
systèmes d'exploitation qui ont un
mécanisme d'élévation des privilèges (c'est le cas de
Windows, comme documenté dans le
blog de Microsoft).Les futures extensions, après ces quatre-là, nécessiteront un examen par l'IETF, via un RFC IETF (cf. RFC 8126, politique « IETF review »). Elle seront placées dans le registre des extensions.
Quelques petits problèmes de déploiement et d'incompatibilité
ont été notés avec ce nouveau
mécanisme d'extensions. Par exemple OpenSSH 7.3 et 7.4 gérait
l'extension server-sig-algs
mais n'envoyait
pas la liste complète des algorithmes acceptés. Un client qui
considérait cette liste comme ferme et définitive pouvait donc
renoncer à utiliser certains algorithmes qui auraient pourtant
marché. Voir ce
message pour une explication détaillée.
Autre gag, les valeurs des extensions peuvent contenir des octets nuls et un logiciel maladroit qui les lirait comme si c'était des chaînes de caractères en C aurait des problèmes. C'est justement ce qui est arrivé à OpenSSH, jusqu'à la version 7.5 incluse, ce qui cassait brutalement la connexion. Le RFC conseille de tester la version du pair, et de ne pas utiliser les extensions en cause si on parle à un OpenSSH ≤ 7.5.
Aujourd'hui, ce mécanisme d'extension est mis en œuvre dans OpenSSH, Bitvise SSH, AsyncSSH et SmartFTP. (Cf. ce tableau de comparaison, mais qui n'est pas forcément à jour.)
Merci à Manuel Pégourié-Gonnard pour avoir détecté une erreur dans la première version.
Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)
Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)