2 votes

Le client Tls 1.3 ne signale pas l'échec du handshake lorsque la vérification du certificat du client par le serveur a échoué

J'ai un client C utilisant OpenSSL qui échoue à un test lorsqu'il utilise un certificat dont la validation échoue du côté du serveur pendant l'appel SSL_do_handshake() sur le serveur. Lorsque l'application utilisait TLS 1.2, l'échec de SSL_do_handshake() sur le serveur était signalé au client comme une valeur de retour d'échec lorsqu'il appelait SSL_do_handshake().

Lors de la mise à niveau de mon application vers OpenSSL 1.1.1 et TLS 1.3, j'ai remarqué que l'erreur de validation se produisait toujours sur le serveur, mais qu'elle n'était plus signalée au client.

Je suis conscient que le protocole de poignée de main a été complètement réécrit dans le cadre de TLS 1.3, mais il me semble qu'avec tous les différents rappels disponibles, je devrais être en mesure, d'une manière ou d'une autre, côté client, de déterminer que l'authentification a échoué sans avoir à tenter d'écrire des données au serveur.

Quelqu'un d'autre a-t-il rencontré ce problème et peut-il recommander une solution ?

2voto

Matt Caswell Points 2199

Dans TLSv1.2 et TLSv1.3, le serveur et le client considèrent que la poignée de main est terminée lorsqu'ils ont tous deux écrit un message "Finished" et reçu un message du pair. Voici à quoi ressemble la poignée de main dans TLSv1.2 (extrait de RFC5246) :

      Client                                               Server

      ClientHello                  -------->
                                                      ServerHello
                                                     Certificate*
                                               ServerKeyExchange*
                                              CertificateRequest*
                                   <--------      ServerHelloDone
      Certificate*
      ClientKeyExchange
      CertificateVerify*
      [ChangeCipherSpec]
      Finished                     -------->
                                               [ChangeCipherSpec]
                                   <--------             Finished
      Application Data             <------->     Application Data

Vous pouvez donc voir ici que le client envoie ses messages Certificate et Finished lors de son deuxième vol de communication avec le serveur. Il attend ensuite de recevoir les messages ChangeCipherSpec et Finished en retour du serveur avant de considérer la poignée de main comme "complète" et de pouvoir commencer à envoyer des données d'application.

Voici le flux équivalent pour TLSv1.3 tiré de la RFC8446 :

       Client                                           Server

Key  ^ ClientHello
Exch | + key_share*
     | + signature_algorithms*
     | + psk_key_exchange_modes*
     v + pre_shared_key*       -------->
                                                  ServerHello  ^ Key
                                                 + key_share*  | Exch
                                            + pre_shared_key*  v
                                        {EncryptedExtensions}  ^  Server
                                        {CertificateRequest*}  v  Params
                                               {Certificate*}  ^
                                         {CertificateVerify*}  | Auth
                                                   {Finished}  v
                               <--------  [Application Data*]
     ^ {Certificate*}
Auth | {CertificateVerify*}
     v {Finished}              -------->
       [Application Data]      <------->  [Application Data]

L'un des avantages de TLSv1.3 est qu'il accélère le temps nécessaire à la réalisation d'une poignée de main. Dans TLSv1.3, le client reçoit du serveur le message "Finished". antes de il renvoie ses messages de Certificat et de Fini. Au moment où le client envoie son message "Finished", il a déjà reçu le message "Finished" et donc la poignée de main est terminée et il peut immédiatement commencer à envoyer des données d'application.

Cela signifie bien sûr que le client ne saura pas si le serveur a accepté ou non le certificat avant de lire les données du serveur. Si le certificat a été rejeté, la prochaine chose que le client lira sera une alerte d'échec (sinon, ce seront des données d'application normales).

Je suis conscient que le protocole de poignée de main a été complètement réécrit dans le cadre de TLS 1.3, mais il me semble qu'avec tous les différents rappels disponibles, je devrais être en mesure, d'une manière ou d'une autre, côté client, de déterminer que l'authentification a échoué sans avoir à tenter d'écrire des données au serveur.

Ce n'est pas l'écriture de données sur le serveur qui est importante - c'est lecture données. Ce n'est qu'à ce moment-là que vous saurez si le serveur a envoyé une alerte ou simplement des données d'application normales. Tant que ces données n'ont pas été lues, aucun rappel n'est disponible dans OpenSSL pour vous le dire, car OpenSSL lui-même ne le sait pas en raison du protocole sous-jacent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X