El estándar TLS actual no es muy claro sobre cómo deben manejarse las versiones. El Anexo E.1 contiene información, de la cual podemos ver que la idea implícita es que la versión seleccionada depende de lo que el cliente y el servidor admiten , no de lo que el cliente y el servidor puede optar por utilizar en un capricho. Si un cliente admite hasta TLS 1.2 y un servidor hasta TLS 1.1, deberían utilizar TLS 1.1, siempre. Como tal, no debería haber ninguna cuestión de "cambiar la versión" al reanudar una sesión o renegociar.
Hay varios campos de versión:
- Cada "registro" tiene un campo de versión.
- El mensaje de ClientHello contiene la versión más alta admitida por el cliente.
- El mensaje de ServerHello contiene la versión que se usará en esta conexión.
Supuestamente, el cliente enviará su primer ClientHello como un registro con un número de versión 3.x para algún valor de "x"; 3.0 maximizará la interoperabilidad. Una vez que el servidor haya respondido con ServerHello indicando que se usará la versión 3.y, el cliente y el servidor deben usar los registros 3.y. Esto hace que la versión salte algo delicada durante una renegociación. Además, los registros TLS 1.1+ cifrados con CBC no son compatibles con los registros SSL 3.0 / TLS 1.0 (debido al IV registro adicional), por lo que las versiones de nivel de registro son importantes una vez que se envía / recibe la primera ChangeCipherSpec.
Para reanudar una sesión, el anexo E.1 establece que:
Cada vez que un cliente ya conoce la versión de protocolo más alta conocida
un servidor (por ejemplo, al reanudar una sesión), DEBERÍA iniciar
la conexión en ese protocolo nativo.
De lo que deduzco que si la sesión anterior usó la versión 3.y, el cliente debería usar records con la versión 3.y. Sin embargo, nada impide que anuncie un número de versión superior en ClientHello.
Además, la derivación de la clave maestra en cifrado y las claves MAC utiliza el PRF de TLS, que depende de la versión del protocolo (TLS 1.0 y 1.1 usan el mismo PRF, pero no SSL 3.0, y tampoco TLS 1.2). Reanudar una sesión con una versión diferente está buscando problemas.
Toda la zona es turbia. Consulte, por ejemplo, este informe de error de Mozilla / Firefox . En mi experiencia, se deben seguir las siguientes reglas para minimizar los problemas:
Reglas para el cliente:
- Envíe el primer registro como versión 3.0.
- Siempre anuncie en ClientHello la versión máxima admitida (por ejemplo, 3.3 para TLS 1.2).
- Cuando el servidor responde con un ServerHello, use la versión enviada por el servidor como nueva versión para todos los registros subsiguientes, cálculos criptográficos y detalles del protocolo.
- Una vez que el servidor haya enviado ServerHello, aplique las versiones de los registros entrantes: los registros subsiguientes del servidor deben usar la versión de que . Si un registro del servidor anuncia otra versión, anule.
- Al renegociar, si el servidor intenta usar una versión diferente a la anterior, anule.
Reglas para el servidor:
- Ignore la versión en los registros entrantes, durante los pasos iniciales de la conexión.
- Una vez que haya enviado su ServerHello, aplique las versiones de registro: todos los registros subsiguientes del cliente deberían usar esa versión.
- Al reanudar una sesión, reutilice la misma versión, siempre que la versión en ClientHello lo permita; de lo contrario, haga un apretón de manos completo (por ejemplo, si la sesión anterior fue TLS 1.1 y el nuevo ClientHello dice 1.2, reanude con la versión 1.1; si la sesión anterior fue TLS 1.1 y el nuevo ClientHello dice 1.0, no reanude, haga un nuevo 1.0 completo apretón de manos).
- Al renegociar, verifique que la versión anunciada en el nuevo ClientHello sea compatible con la versión actual, pero no cambie la versión actual. Si el primer saludo fue 1.1, el segundo será 1.1, incluso si el nuevo ClientHello dice 1.2.
Está bastante garantizado que hay implementaciones ampliamente implementadas que se equivocan en algún momento.