Veamos un ejemplo de una conexión HTTP usando TLS como protocolo de transporte para los datos. A esta combinación de protocolos se la conoce comunmente como HTTPS, donde los mensajes HTTP se envían encriptados usando TLS (o SSL) como el protocolo de transporte.
El server común de HTTP (donde los datos viajan sin seguridad alguna) toma los pedidos de clientes sobre el port 80, mientras que HTTPS usa el port 443, proveyendo la protección brindada por TLS para todos los mensajes HTTP.
A modo ilustrativo, se detalla una tabla con los distintos protocolos capaces de soportar TLS como medio de transporte, y el número de port que utiliza (sobre TCP):
Clave | Configuración | Port | Proposito |
---|---|---|---|
https | HTTP/TLS | 443 | HTTP (WWW) protegido con TLS |
ssmtp | SMTP/TLS | 465 | SMTP (envío de email) protegido con TLS |
snews | NNTP/TLS | 563 | NNTP (Usenet news) protegido con TLS |
ssl-ldap | LDAP/TLS | 636 | LDAP (directorio) protegido con TLS |
spop3 | POP3/TLS | 995 | POP3 (recepción de email) protegido con TLS |
Ahora presentaremos el ejemplo: Una persona inicia un Web Browser y tipea la siguiente URL:
https://bijou.mcom.com/bar
Veremos los pasos que toma el browser y el servidor de HTTPS
para satisfacer el pedido.
Se utilizará un diagrama de linea de tiempo para mostrar la
secuencia de pasos.
Los certificados y claves públicas y privadas usadas (y reveladas) en este ejemplo, se usan solamente para entender lo que esta pasando, y se dan a conocer solo con estos fines ejemplificativos.
La conexión usa autenticación del server y del cliente. Como algoritmo de encriptación usa el RC4 (un stream cipher, por lo tanto no necesita IVs, aunque en el ejemplo se indique que se generan. Esto es solo para hacer el ejemplo más generico) con una clave de 128 bits (es no exportable, o sea que solamente se usa para conexiones entre US y Canada, pero esto no invalida la utilidad del ejemplo). Como función para el MAC se usa MD5.
Hay dos formas de realizar el handshake para iniciar una conexión TLS:
Handshake Completo: Se lleva a cabo el handshake completo para iniciar una conexión, lo cual puede incluir no autenticar las partes, autenticar el server, o autenticar el server y el cliente. Se elije el ciphersuite a usar y se intercambian las claves y secretos. | |
Handshake Abreviado: Se lleva a cabo el handshake abreviado para reanudar una conexión previa mantenida en el cache del server. Solo se verifican los parámetros del ciphersuite a usar. |
Esta tabla muestra los diferentes mensajes en la conexión completa. Cada link lo llevará a la explicación del mensaje.
Cliente | Server |
---|---|
Client Hello | |
Server Hello | |
Certificate | |
Server Key Exchange | |
Certificate Request | |
Server Hello Done | |
Client Certificate | |
Client Key Exchange | |
Certificate Verify | |
Change Cipher Spec | |
Finished | |
Change Cipher Spec | |
Finished | |
HTTP request | |
HTTP response | |
Close Notify Alert | |
Close Notify Alert |
Una vez que el cliente (web browser) ingresa la URL https://bijou.mcom.com/bar, el browser hace llama al parser para que decodifique la URL ingresada. Este se da cuenta que el protocolo elegido es https, e inmediatamente (la biblioteca utilizada para tener capacidad de usar TLS, como SSLRef, SSLeay o SSL Java que tengan soporte para TLS) crea un socket al host bijou.mcom.com (el "supuesto" server) al port 443 (el predefinido para HTTP/TLS cuando el protocolo de transporte es TCP).
Una vez creado el socket, el cliente manda un mensaje ClienteHello al server, en el cual van:
La versión es TLS v1.0, o sea que le manda los números {3, 1}, por razones de compatibilidad con SSL. | |
Bytes random, los cuales luego se usan para verificar la integridad de los mensajes enviados sin protección y para crear el master secret. | |
La session-id con longitud 0, indicando que va a realizar el handshake completo, y que esta va a establecer nuevos parámetros de seguridad (o ciphersuite). | |
Los ciphersuites favoritos del cliente, con los cuales quiere que se proteja la conexión. En este caso, el primer ciphersuite (y el más favorito) de la lista es TLS_RSA_WITH_RC4_128_MD5, el segundo podria ser TLS_DHE_DSS_WITH_DES_CBC_SHA, y luego pueden venir otros (no tienen importancia para el ejemplo). | |
El método de compresión va a ser nulo, es decir que no va a haber compresión. |
Por supuesto, este mensaje, que pertenece al Handshake Protocol se encapsula en una estructura TLSPlaintext, y luego ésta en una estructura TLSCiphertext, las cuales mensajes del Record Protocol.
El cliente ingresa este mensaje en las funciones de hashing MD5 y SHA para poder verificar luego que los mensajes no hayan sido falsificados.
Ahora, el cliente se queda esperando la respuesta del server.
El server recibe el mensaje ClienteHello, y genera un mensaje ServerHello (indicando al cliente los parámetros que aceptará para la conexión) con los siguientes datos:
La versión de TLS que soporta el server, que en este caso soporta TLS v1.0, y entonces envia {3,1}. (Si hubiese soportado solo SSL v3.0 hubiese enviado {3,0}, y el cliente tendrá que trabajar con SSL v3.0). | |
Bytes random generados por el server, que deben ser diferentes a los del cliente, enviados en el mensaje ClienteHello. | |
La identidad de la sesión (session-id) que el server asignó para esta conexión. | |
El ciphersuite "más favorito" del cliente que soporta este server. En este caso, el server soporta el primero de la lista (TLS_RSA_WITH_RC4_128_MD5), con lo cual lo elige inmediatamente. Además puede elegirlo porque el server esta en US o Canada. | |
El algoritmo de compresión va a ser nulo (sin compresión), ya que el cliente lo pidió así. |
La session_id es no nula, lo que significa que la sesión puede ser reanudada. ¿Puede que sea mejor hacer que la session_id sea siempre de 32 bytes, para evitar posibles ataques basados en la longitud del registro?
A continuación, como el cliente eligió el ciphersuite TLS_RSA_WITH_RC4_128_MD5, el cual requiere autenticación del server, éste envía su lista de certificados (o cadena de certificados) para que el cliente pueda autenticarlo, en un mensaje Certificate, con los siguientes datos:
La lista de certificados, la cual en este ejemplo, es: | |||||
|
Esta lista es la cadena de certificados para poder autenticar el server. El primero es el certificado del server. Para detalles de cómo el cliente autentica al server ver Autenticación del Server.
En este caso, este mensaje no se genera, ya que el método usado para intercambiar el pre-master secret es RSA, y los certificados mandados en Certificate ya contiene la clave pública del server para que el cliente pueda hacer el intercambio, entonces no se necesita mandar ningún otro parámetro (por parte del server) para que el cliente pueda realizar el intercambio.
El server determina que debe autenticar al cliente (porque el servicio que presta así lo require). Par ello genera el mensaje CertificateRequest, en el cual se especifica la lista de CAs en los que confia este server, y los tipos de certificados requeridos, ordenados por preferencia del server. Los datos del mensaje son:
La lista de tipos de certificados requeridos son {rsa_sign, dss_sign}, es decir, que este server requiere certificados firmados con RSA o DSS, y prefiere los firmados con RSA. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
La lista de DNs (Distinguished Names) de los CA aceptables por el server. En este ejemplo, la lista contiene los siguienetes DNs (los strings siguientes son representativos, no son los verdaderos DNs): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
La lista de DNs representa la lista de CAs en las que confia el server para autenticar al cliente. Para detalles de cómo el server autentica al cliente ver Autenticación del Cliente.
Una vez generado el mensaje CertificateRequest, se genera el mensaje ServerHelloDone, que indica el fin del Hello del server. El server envia todos los mensajes juntos, desde el SeverHello hasta el ServerHelloDone en este momento y se queda esperando la respuesta del cliente.
Ahora, estos cuatro mensajes son mandados al cliente en un solo registro (o en varios si el Record Protocol tiene que fragmentarlo). No se genera ni el MAC, ni se hace compresión, ni se encripta el registro, ya que ningún registro change_cipher_spec ha sido mandado aún. Los parámetros de seguridad (ciphersuite) elegidos pasan a ser el Estado Pendiente de TLS.
Todos los mensajes del Handshake Protocol anteriores (incluido el ClientHello recibido) se pasan por las funciones de hashing MD5 y SHA para poder verificar luego que no hayan sido falsificados.
Cuando el cliente recibe los mensajes del server, éste se fija el ciphersuite elegido por el server, el cual viene en el mensaje ServerHello, para saber si el ciphersuite elegido por el server tiene parámetros de seguridad aceptables por el cliente. En este caso el server eligió usar el TLS_RSA_WITH_RC4_128_MD5, el cual es el preferido del cliente. Si el ciphersuite recibido fuese inaceptable para el cliente (esto es, no aparece en la lista de ciphersuites en el mensaje ClientHello), se envia al server un mensaje de error y se aborta el handshake.
Como el ciphersuite elegido requiere autenticación del
server, el cliente recibe también el mensaje Certificate con
la cadena de certificados del server. El cliente ahora procede a
autenticar al server, como se indica en Autenticación del
Server. Si el server puede ser autenticado el cliente
prosigue con el handshake, de lo contrario se aborta el
handshake.
Acá se supone que el server pudo ser autenticado.
También se recibe el mensaje CertificateRequest, el cual le dice al cliente que debe ser autenticado para poder utilizar el servicio requerido (en este caso, el servicio es poder transferir una página HTML al browser).
Como recibió el mensaje mensionado arriba, el cliente debe responder con una lista de certificados de cliente, para que el server lo pueda autenticar. Por lo tanto se genera un mensaje Certificate, similar al enviado por el server.
Los datos del mensaje son:
La lista de certificados del cliente, la cual en este ejemplo, es: | |||||
|
Esta lista es la cadena de certificados para poder autenticar al cliente. El primero es el certificado del cliente. Para detalles de cómo el server autentica al cliente ver Autenticación del Cliente.
Para hacer el intercambio del pre-master secret, se genera un mensaje ClientKeyExchange. El pre-master secret es un secreto compartido entre el cliente y el server para que luego puedan generar el master secret, y subsecuentemente las claves de sesión, los secretos MAC y los IVs.
El pre-master secret son 46 bytes de datos generados aleatoriamente (más 2 bytes de la versión de TLS que usa el cliente, para evitar ataques de tipo version-rollback [8]) por el cliente, que se envían encriptados con la clave pública del server, la cual se obtuvo del certificado X.509v3 del server.
Antes de la encriptación, el pre-master secret se formatea como se indica en [9].
Antes de mandar el mensaje client_key_exchange, el cliente calcula el master secret como se describe en Generación de Claves, y luego calcula el "key block", a partir del cual se derivan los MAC Secrets, las session keys y los IVs.
Como es un cliente de US o Canada, las claves de sesion y los
IVs se toman directamente del "key block".
Ya que en este ejemplo usamos un stream cipher (RC4), los
cuales no requieren IVs, éstos valores se ignoran en el key
block.
Para probar que los datos que se han recibido y enviado no han sido ni falsificados ni modificados, se genera el mensaje CertificateVerify. Tanto el cliente como el server ingresan todos los mensajes del Handshake Protocol (los recibidos y los enviados hesde el comienzo del handshake) en las funciones de hashing MD5 y SHA.
Para evitar que los valores generados por MD5 y SHA sean falsificados o modificados, se firma digitalmente con la clave privada del cliente (la cual él solo conoce). Previo a la firma, el plaintext se formatea como dice en [9].
Cuando el server reciba este mensaje, debe calcular las hashes MD5 y SHA tal cual lo hizo el cliente, y comparar el resultado calculado con lo que recibió en este mensaje. Si los valores coinciden, entonces se prosigue con el handshake, sino se aborta el handshake.
El mensaje ChangeCipherSpec se utiliza para indicar al server que debe hacer de su estado pendiente (los parámetros de seguridad negociados en este handshake) su estado corriente. Esto significa que los siguientes registros que se envíen desde el cliente al server serán protegidos con el ciphersuite y claves negociados.
Este mensaje se genera para verificar con el server que los parámetros de seguridad fueron correctamente calculados por ambos. El mensaje Finished consta de 12 bytes generados con la PRF a partir del master secret, y los hashes MD5 y SHA calculados hasta ahora.
El Record Protocol va a calcular el MAC de este mensaje con MD5, y luego va a encriptarlo con RC4, es decir, se utilizará el ciphersuite negociado.
En este punto, se envían al server todos los mensajes anteriores, desde ClientCertificate hasta Finished inclusive.
El cliente se queda esperando la respuesta del server.
El server recibe la respuesta del cliente.
Primero recibe el mensaje Certificate del cliente en el cual viaja la cadena de certificados del cliente. El server trata de autenticar al cliente como se describe en Autenticación del Cliente, y si puede autenticarlo prosigue con el proximo mensaje recibido del cliente, de lo contrario aborta el handshake.
Suponiendo que pudo autenticar al cliente, procesa el mensaje ClientKeyExchange,
en el que viaje el pre-master secret necesario para generar las
claves de sesión, los secretos del MAC y los IVs.
El server desencripta el contenido del mensaje usando su clave
pública.
Procesa el mensaje CertificateVerify, que contiene los hashes generados por el cliente. Desencripta los hashes con la clave pública del cliente (que viene en el certificado del cliente). Compara los hashes MD5 y SHA calculados por el server con los enviados por el cliente y si son iguales el server continua con el handshake, sino lo aborta.
Suponemos que los hashes coincidieron, el server procesa el mensaje ChangeCipherSpec enviado por el cliente, que tiene el efecto de cambiar el estado corriente (sin encriptación ni MAC) por el estado pendiente (encriptación con RC4 y MAC con MD5). A partir de este momento, el server enviará y recibirá mensajes protegidos con el ciphersuite negociado.
El server procesa ahora el mensaje Finished que envió el cliente. Este mensaje viene protegido con el nuevo ciphersuite, y el cliente lo envia para verificar que los parámetros sean correctos. El server desencripta el mensaje con RC4 usando su clave de lectura, genera el MAC con su secreto MAC de lectura ycompara con el del cliente para verificar que el mensaje no ha sido modificado, y genera los 12 bytes random de la misma forma que el cliente, si coinciden, entonces este sentido de la conexión ha sido verificado.
Ahora el server genera un mensaje ChangeCipherSpec, para que el cliente cambie el estado corriente de lectura con el estado pendiente de lectura, para poder usar el nuevo ciphersuite en este sentido de la conexión.
El server genera 12 bytes random con la PRF de forma muy similar a como lo hizo el cliente en su mensaje Finished, usando el master secret y las hashes calculadas hasta ahora.
Estos 12 bytes los encapsula en un mensaje Finished, genera el MAC con MD5, y encripta todo con la clave de escritura de RC4.
Luego envía estos dos últimos mensajes al cliente. En este momento la conexión ya está lista para transportar en forma segura datos de la capa de aplicación, salvo que el cliente envíe un mensaje de Alerta para abortar la conexión.
El cliente recibe el mensaje ChangeCipherSpec del server, y cambia el estado de lectura corriente con el estado de lectura pendiente.
Ahora, el cliente recibe el mensaje Finished del server y chequea que la conexión en este sentido tenga los parámetros de seguridad correctos desencriptando el mensaje, comparando el MAC y chequeando los 12 bytes random generados por el server.
Si no se encontro ningún error, el cliente se dispone a hacer el pedido al server. En caso contrario se aborta la conexión enviando un mensaje de Alerta al server.
No habiendo errores en el handshake, el cliente (Web browser) se dispone ha hacer el pedido al servidor Web:
GET /bar HTTP/1.0 Connection: Keep-Alive User-Agent: Mozilla/4.02 [en] (WinNT; U) Host: bijou.mcom.com:1999 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* Accept-Languaje: en-US,en-GB,en Accept-Charset: iso-8859-1,*,utf-8 |
Este mensaje se encapsula en un registro del Record Protocol, se genera el MAC, se encripta y se envía al server.
En este ejemplo, la respuesta del server se envía en tres registros secuenciales de datos:
HTTP/1.0 200 OK Server: Netscape-Enterprise/2.0a Date: Tue, 28 Apr 1999 22:10:05 GMT Content-type: text/plain |
GET /bar HTTP/1.0 Connection: Keep-Alive User-Agent: Mozilla/4.02 [en] (WinNT; U) Host: bijou.mcom.com:1999 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* Accept-Languaje: en-US,en-GB,en Accept-Charset: iso-8859-1,*,utf-8 |
EOF |
Este mensaje se encapsula en tres registros del Record Protocol, se genera el MAC, se encriptan y se envían al cliente.
El resto de la comunicación es de la misma forma para todos los datos del nivel de aplicación que se quieran transferir.
Finalmente, el server manda un Alerta Close Notify para indicarle al cliente que el server terminó. Por supuesto, este mensaje se envía protegido por el ciphersuite.
Dependiendo del protocolo de aplicación que esté usando la conexión, el servidor podría decidir esperar a que llegue el Close Notify del cliente para cerrar el socket TLS, o bién cerrarlo sin esperar el Close nofity. En este caso, no se espera a que llegue el otro Close Notify.
El cliente recibe un Close Notify del server y responde con otro Close Notify para cerrar la sesión. Se envía protegido y se cierra el socket sobyacente.
Esta tabla muestra los diferentes mensajes en la conexión abreviada. Cada link lo llevará a la explicación del mensaje.
Cliente | Server |
---|---|
ClientHello | |
ServerHello | |
ChangeCipherSpec | |
Finished | |
ChangeCipherSpec | |
Finished | |
Datos de Aplicación <-----> | <-----> Datos de Aplicación |
En una forma resumida, el handshake es como sigue:
El cliente envía un ClientHello usando el session-ID de la sesión a ser reanudada y otros 48 bytes random. El server luego chequea en su cache de sesiones para ver si encuentra esa sesión. Si se encuentra la sesión, y el server está dispuesto a reestablecer la conexión bajo el estado especificado de sesión, mandará un ServerHello con el mismo valor de session-ID y otros 48 bytes random. Se debe regenerar el master secret y las claves de sesión, los secretos MAC y los IVs. En este punto tanto el cliente como el server deben enviar directamente mensajes ChangeCipherSpec y Finished. Una vez que el reestablecimiento esta completo, el cliente y server empiezan a intercambiar datos de aplicación.
Si el server no puede encontrar el session-ID en su cache, el server genera una nuevo session-ID y tanto el cliente como el server TLS ejecutan un handshake completo.