web-dev-qa-db-fra.com

Comment gérer OpenSSL SSL_ERROR_WANT_READ / WANT_WRITE sur des sockets non bloquants

La bibliothèque OpenSSL permet de lire à partir d'un socket sous-jacent avec SSL_read et d'y écrire avec SSL_write. Ces fonctions peuvent retourner avec SSL_ERROR_WANT_READ ou SSL_ERROR_WANT_WRITE en fonction de leurs besoins de protocole SSL (par exemple lors de la renégociation d'une connexion).

Je ne comprends pas vraiment ce que l'API veut que je fasse avec ces résultats.

Imager une application serveur qui accepte les connexions client, configure une nouvelle session SSL, rend le socket sous-jacent non bloquant, puis ajoute le descripteur de fichier à une boucle select/poll/epoll.

Si un client envoie des données, la boucle principale enverra cela à un ssl_read. Que faut-il faire ici si SSL_ERROR_WANT_READ ou SSL_ERROR_WANT_WRITE est retourné? WANT_READ pourrait être facile, car la prochaine itération de la boucle principale pourrait simplement conduire à un autre ssl_read. Mais si ssl_read retourne WANT_WRITE, avec quels paramètres faut-il l'appeler? Et pourquoi la bibliothèque ne lance-t-elle pas l'appel lui-même?

Si le serveur veut envoyer des données à un client, il utilisera ssl_write. Encore une fois, que faire si WANT_READ ou WANT_WRITE sont retournés? Peut-on répondre à WANT_WRITE en répétant le même appel qui vient d'être appelé? Et si WANT_READ est retourné, doit-on retourner à la boucle principale et laisser le select/poll/epoll s'en occuper? Mais qu'en est-il du message qui devrait être écrit en premier lieu?

Ou la lecture doit-elle être effectuée juste après l'échec de l'écriture? Ensuite, qu'est-ce qui protège contre la lecture d'octets du protocole d'application et ensuite le traitement quelque part en périphérie de l'application, lorsque le véritable analyseur se trouve dans la boucle principale?

38
dantje

Avec des sockets non bloquants, SSL_WANT_READ Signifie "attendez que le socket soit lisible, puis appelez à nouveau cette fonction."; à l'inverse, SSL_WANT_WRITE signifie "attendez que le socket soit accessible en écriture, puis appelez à nouveau cette fonction.". Vous pouvez obtenir SSL_WANT_WRITE Ou SSL_WANT_READ À la fois à partir d'un appel SSL_read() ou SSL_write().

55
caf

Avez-vous déjà lu la documentation OpenSSL pour ssl_read et ssl_get_error ?

ssl_read:

Si le BIO sous-jacent se bloque, SSL_read () ne reviendra que lorsque l'opération de lecture sera terminée ou qu'une erreur se produira, sauf lorsqu'une renégociation a lieu, auquel cas un SSL_ERROR_WANT_READ peut se produire. Ce comportement peut être contrôlé avec l'indicateur SSL_MODE_AUTO_RETRY de l'appel SSL_CTX_set_mode (3).

Si le BIO sous-jacent n'est pas bloquant, SSL_read () retournera également lorsque le BIO sous-jacent n'a pas pu satisfaire les besoins de SSL_read () pour continuer l'opération. Dans ce cas, un appel à SSL_get_error (3) avec la valeur de retour de SSL_read () donnera SSL_ERROR_WANT_READ ou SSL_ERROR_WANT_WRITE. Comme à tout moment une renégociation est possible, un appel à SSL_read () peut également provoquer des opérations d'écriture! Le processus appelant doit alors répéter l'appel après avoir pris les mesures appropriées pour satisfaire les besoins de SSL_read (). L'action dépend du BIO sous-jacent. Lorsque vous utilisez un socket non bloquant, rien ne doit être fait, mais select () peut être utilisé pour vérifier la condition requise.

ssl_get_error:

SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE

L'opération n'est pas terminée; la même fonction d'E/S TLS/SSL doit être rappelée ultérieurement. Si, d'ici là, le BIO sous-jacent a des données disponibles pour la lecture (si le code de résultat est SSL_ERROR_WANT_READ) ou autorise l'écriture de données (SSL_ERROR_WANT_WRITE), alors une progression du protocole TLS/SSL aura lieu, c'est-à-dire au moins une partie d'un enregistrement TLS/SSL sera lu ou écrit. Notez que la nouvelle tentative peut à nouveau conduire à une condition SSL_ERROR_WANT_READ ou SSL_ERROR_WANT_WRITE. Il n'y a pas de limite supérieure fixe pour le nombre d'itérations qui peuvent être nécessaires jusqu'à ce que les progrès deviennent visibles au niveau du protocole d'application.

Pour les BIO de socket (par exemple lorsque SSL_set_fd () a été utilisé), select () ou poll () sur le socket sous-jacent peuvent être utilisés pour savoir quand la fonction d'E/S TLS/SSL doit être réessayée.

Avertissement: Toute fonction d'E/S TLS/SSL peut conduire à SSL_ERROR_WANT_READ et SSL_ERROR_WANT_WRITE. En particulier, SSL_read () ou SSL_peek () peut vouloir écrire des données et SSL_write () peut vouloir lire des données. Cela est principalement dû au fait que des négociations TLS/SSL peuvent se produire à tout moment pendant le protocole (initiées par le client ou le serveur); SSL_read (), SSL_peek () et SSL_write () gèreront toutes les poignées de main en attente.

OpenSSL est implémenté comme une machine d'état. SSL_ERROR_WANT_READ signifie que davantage de données entrantes et SSL_ERROR_WANT_WRITE signifie que davantage de données sortantes sont nécessaires pour faire avancer la connexion. Si vous obtenez SSL_ERROR_WANT_WRITE lors d'une opération ssl_read (), vous devez envoyer des données sortantes, ou au moins attendre que le socket devienne accessible en écriture. Si vous obtenez SSL_ERROR_WANT_READ lors d'une opération ssl_write (), vous devez lire les données entrantes.

Vous devez vous abonner aux listes de diffusion OpenSSL . Cette question est souvent posée.

16
Remy Lebeau

SSL_WANT_READ signifie que le moteur SSL ne peut actuellement pas crypter pour vous car il attend plus de données d'entrée (soit dans le cadre de la prise de contact initiale ou dans le cadre d'une renégociation), donc, une fois votre prochaine lecture terminée et vous avez poussé le les données qui sont arrivées via le moteur SSL, vous pouvez réessayer votre opération d'écriture.

De même, SSL_WANT_WRITE signifie que le moteur SSL vous attend pour en extraire certaines données et les envoyer au pair.

J'ai écrit sur l'utilisation d'OpenSSL avec des sockets non bloquants et asynchrones en 2002 pour Windows Developer Journal (réimprimé ici ) et bien que cet article vise ostensiblement le code Windows, les principes sont les mêmes pour les autres plates-formes. L'article est livré avec du code qui intègre OpenSSL avec des sockets asynchrones sous Windows et qui traite de l'ensemble du problème SSL_WANT_READ/SSL_WANT_WRITE.

Essentiellement, lorsque vous obtenez un SSL_WANT_READ, vous devez mettre les données sortantes en file d'attente jusqu'à ce que vous ayez terminé la lecture et que vous ayez transmis les nouvelles données entrantes dans le moteur SSL, une fois que cela s'est produit, vous pouvez réessayer d'envoyer vos données sortantes.

7
Len Holgate