Resumen

  • CertificateVerify firma el transcript con la clave privada del certificado; Finished usa una clave derivada del secreto de tráfico de handshake del emisor para autenticar otra frontera.
  • Un Finished de servidor válido no acredita el Finished cliente, 0-RTT aceptado, el tramo ascendente de un proxy, autorización de aplicación ni resultado durable.

Un mensaje separaba el éxito del fracaso

La cadena y el nombre de servicio eran aceptables. La firma CertificateVerify también. Pero el verify_data recibido después no concordó con el transcript y la clave calculados por el cliente. RFC 9846 exige terminar la conexión. No hubo una sesión ordinaria parcialmente buena; hubo un handshake fallido.

CertificateVerify demuestra control de la clave privada asociada a la credencial. Firma una construcción separada por rol y basada en el transcript hasta Certificate. La política de ruta y de identidad sigue siendo independiente.

Finished no vuelve a firmar con la clave del certificado. Deriva finished_key del secreto de tráfico de handshake de quien envía y calcula un HMAC sobre el transcript hasta CertificateVerify, si existe. Confirma el material secreto y la historia exacta de esa conexión.

En PSK pueden faltar Certificate y CertificateVerify, pero Finished sigue siendo obligatorio. Por eso ninguna de las dos pruebas sustituye a la otra.

El transcript tiene reglas propias

El hash incorpora mensajes de handshake en orden, con sus cabeceras de tipo y longitud. No incorpora cabeceras de record, alertas ni datos de aplicación. La fragmentación de records no redefine la historia lógica.

HelloRetryRequest sustituye el primer ClientHello por un message_hash sintético. Una captura no puede concatenar bytes visibles y llamarlos transcript. Además, los mensajes posteriores de TLS 1.3 están cifrados: reconstruirlos exige secretos diagnósticos del extremo o evidencia equivalente de la implementación.

El hash de la suite gobierna transcript y HKDF. verify_data mide la salida de ese hash; no conserva los doce octetos fijos de TLS 1.2.

La finalización pertenece a un lado

Cliente y servidor derivan secretos distintos, producen Finished distintos y verifican al par en momentos distintos. Tras enviar su Finished, el servidor puede usar claves de aplicación e incluso enviar datos antes del Finished cliente. Todavía no tiene garantía de identidad o presencia del cliente, pues el ClientHello pudo reproducirse.

El cliente verifica el Finished servidor, responde con su autenticación si fue solicitada y envía el suyo. Un tls_complete único borra qué prueba existe. Conviene registrar por extremo finished_sent, peer_finished_verified y el estado comprobado de la biblioteca.

0-RTT es una excepción explícita. Puede viajar antes de verificar el Finished servidor, depende de un PSK antiguo y admite repetición. Hay que separar oferta, aceptación o rechazo de early data, verificación de Finished y tráfico ordinario.

Dos tramos de proxy nunca son una sola prueba

Cliente–proxy y proxy–origen tienen transcript, secretos y Finished propios. Copiar el estado del tramo descendente al ascendente inventa continuidad. La correlación de aplicación puede enlazar solicitudes, pero el origen necesita la prueba de su propio handshake.

OpenSSL distingue el estado de handshake de SSL_get_verify_result(), que sólo informa de certificado. El key log permite una comprobación aislada, pero expone secretos. BoringSSL documenta que sus accesores Finished devuelven cero en TLS 1.3; GnuTLS ofrece hooks y un error específico. La observabilidad debe probarse por biblioteca, no inferirse por nombres parecidos.

La prueba negativa conserva certificado y CertificateVerify, cambia un byte de Finished y exige fallo fatal. Luego retiene el Finished cliente, ejecuta PSK sin certificado, fuerza HelloRetryRequest y repite con parámetros diferentes en cada tramo del proxy. Sólo ese comportamiento demuestra la frontera en código activo.