linux sockets openssl

linux - Cómo manejar OpenSSL SSL_ERROR_WANT_READ/WANT_WRITE en sockets no bloqueantes



(3)

La biblioteca OpenSSL permite leer desde un socket subyacente con SSL_read y escribir en él con SSL_write. Estas funciones tal vez regresen con SSL_ERROR_WANT_READ o SSL_ERROR_WANT_WRITE según sus necesidades de protocolo ssl (por ejemplo, cuando se renegocia una conexión).

Realmente no entiendo lo que la API quiere que haga con estos resultados.

Imagine una aplicación de servidor que acepta conexiones de cliente, configura una nueva sesión de SSL, no bloquea el socket subyacente y luego agrega el descriptor de archivo a un ciclo select / poll / epoll.

Si un cliente envía datos, el ciclo principal lo enviará a un ssl_read. ¿Qué se debe hacer aquí si se devuelve SSL_ERROR_WANT_READ o SSL_ERROR_WANT_WRITE? WANT_READ podría ser fácil, porque la siguiente iteración del bucle principal podría conducir a otro ssl_read. Pero si el ssl_read devuelve WANT_WRITE, ¿con qué parámetros debería llamarse? ¿Y por qué la biblioteca no emite la llamada en sí?

Si el servidor desea enviar datos a un cliente, usará ssl_write. De nuevo, ¿qué hacer si se devuelven WANT_READ o WANT_WRITE? ¿Se puede responder a WANT_WRITE repitiendo la misma llamada que recién se invocó? Y si se devuelve WANT_READ, ¿debería uno volver al ciclo principal y dejar que el select / poll / epoll se encargue de esto? Pero, ¿qué pasa con el mensaje que debería escribirse en primer lugar?

¿O debería hacerse la lectura justo después de la escritura fallida? Entonces, ¿qué protege contra la lectura de bytes del protocolo de la aplicación y luego tener que lidiar con él en algún lugar en las afueras de la aplicación, cuando el analizador real se encuentra en el bucle principal?


¿Leyó la documentación de OpenSSL para ssl_read y ssl_get_error todavía?

ssl_read:

Si el BIO subyacente está bloqueando, SSL_read () solo volverá, una vez que la operación de lectura haya finalizado o se haya producido un error, excepto cuando tenga lugar una renegociación, en cuyo caso puede producirse un SSL_ERROR_WANT_READ. Este comportamiento se puede controlar con el indicador SSL_MODE_AUTO_RETRY de la llamada SSL_CTX_set_mode (3).

Si el BIO subyacente no es de bloqueo, SSL_read () también regresará cuando el BIO subyacente no pueda satisfacer las necesidades de SSL_read () para continuar la operación. En este caso, una llamada a SSL_get_error (3) con el valor de retorno de SSL_read () arrojará SSL_ERROR_WANT_READ o SSL_ERROR_WANT_WRITE. Como en cualquier momento es posible una renegociación, una llamada a SSL_read () también puede provocar operaciones de escritura. El proceso de llamada luego debe repetir la llamada después de tomar las medidas apropiadas para satisfacer las necesidades de SSL_read (). La acción depende del BIO subyacente. Cuando se usa un socket no bloqueante, no se debe hacer nada, pero select () se puede usar para verificar la condición requerida.

ssl_get_error:

SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE

La operación no se completó; la misma función de E / S TLS / SSL se debe volver a llamar más tarde. Si, para entonces, el BIO subyacente tiene datos disponibles para leer (si el código de resultado es SSL_ERROR_WANT_READ) o permite escribir datos (SSL_ERROR_WANT_WRITE), se realizará algún progreso del protocolo TLS / SSL, es decir, al menos parte de un registro TLS / SSL será leído o escrito Tenga en cuenta que el reintento nuevamente puede generar una condición SSL_ERROR_WANT_READ o SSL_ERROR_WANT_WRITE. No hay un límite superior fijo para la cantidad de iteraciones que pueden ser necesarias hasta que el progreso sea visible en el nivel de protocolo de la aplicación.

Para los BIO de socket (por ejemplo, cuando se usó SSL_set_fd ()), select () o poll () en el socket subyacente se pueden usar para averiguar cuándo se debe reintentar la función de E / S TLS / SSL.

Advertencia: cualquier función de E / S TLS / SSL puede generar SSL_ERROR_WANT_READ y SSL_ERROR_WANT_WRITE. En particular, SSL_read () o SSL_peek () pueden querer escribir datos y SSL_write () puede querer leer datos. Esto se debe principalmente a que los apretones de manos TLS / SSL pueden ocurrir en cualquier momento durante el protocolo (iniciado por el cliente o el servidor); SSL_read (), SSL_peek () y SSL_write () se encargarán de cualquier saludo de mano pendiente.

OpenSSL se implementa como una máquina de estado. SSL_ERROR_WANT_READ significa que hay más datos entrantes y SSL_ERROR_WANT_WRITE significa que se necesitan más datos de salida para avanzar el progreso de la conexión. Si obtiene SSL_ERROR_WANT_WRITE en una operación ssl_read (), debe enviar datos salientes, o al menos esperar a que el socket se pueda escribir. Si obtiene SSL_ERROR_WANT_READ en una operación ssl_write (), debe leer los datos entrantes.

Debe suscribirse a las listas de correo de OpenSSL . Esta pregunta se pregunta mucho.


SSL_WANT_READ significa que el motor SSL no puede encriptar en ese momento, ya que está esperando más datos de entrada (ya sea como parte del saludo inicial o como parte de una renegociación), así que, una vez que su próxima lectura se haya completado y haya presionado el Los datos que llegaron a través del motor SSL pueden volver a intentar su operación de escritura.

Del mismo modo, SSL_WANT_WRITE significa que el motor SSL está esperando que usted extraiga algunos datos y los envíe al par.

Escribí sobre el uso de OpenSSL con sockets no bloqueantes y asíncronos en 2002 para Windows Developer Journal (reimpreso here ) y, aunque este artículo está aparentemente dirigido al código de Windows, los principios son los mismos para otras plataformas. El artículo viene con un código que integra OpenSSL con conectores asíncronos en Windows y que trata el problema SSL_WANT_READ / SSL_WANT_WRITE completo.

Básicamente, cuando obtienes SSL_WANT_READ necesitas poner en cola los datos salientes hasta que hayas completado una lectura y hayas pasado los nuevos datos entrantes al motor SSL, una vez que esto haya sucedido, puedes volver a enviar los datos salientes.


Con los zócalos sin bloqueo, SSL_WANT_READ significa "esperar a que el zócalo sea legible, luego llamar de nuevo a esta función". ; por el contrario, SSL_WANT_WRITE significa "esperar a que el socket sea grabable, luego llamar de nuevo a esta función". . Puede obtener SSL_WANT_WRITE o SSL_WANT_READ de una SSL_read() o SSL_write() .