Para comenzar una conexión protegida, TLS requiere la especificación de un conjunto de algoritmos, el master secret, y valores random del cliente y servidor. Los algoritmos de autenticación, encriptación y MAC están determinados por el chiper_suite seleccionado por el server y dados a conocer en el hello message. Los algoritmos de compressión son negociados en hello message, y además los valores random son intercambiados . Todo lo restante se calcula en el master secret.
En TLS , antes de una encriptación o verificación de integridad sobre los registros, el cliente y el servidor necesitan generar información secreta compartida conocida sólo por ellos. Este valor de 48 bytes es llamado master_secret y es usado para generar claves y secretos para la encriptación y computación del MAC. El master_secret es usado sólo para la computación del MAC.
Para generar el master_secret se utiliza la función PRF:
master_secret | = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random)[0..n] |
Recordemos que la función PRF se obtiene como:
PRF(secret, label, seed) | = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed) |
Para generar las claves y los secretos MAC , se computa un vector con valores pseudoaleatorios llamado key_block . Para generar este vector se usa el master_secret el cual es usado como una fuente de entropía y los valores aleatorios generados por la PRF se usan para las otras claves y los IVs para los ciphers exportables.
key_block | = PRF(SecurityParameters.master_secret, " Key expansion", SecurityParameters.server_random + SecurityParameters.clients_random) |
Luego el Key_block es particionado para generar los siguientes vectores:
client_write_MAC_secret[CipherSpec.hash_size]
server_write_MAC_secret[CipherSpec.hash_size]
client_write_key[CipherSpec.key_material]
server_write_key[CipherSpec.key_material]
client_write_IV[CipherSpec.IV_size] /* ciphers no exportables*/
server_write_IV[CipherSpec.IV_size] /* ciphers no exportables*/
Como podemos ver arriba, el client_write_IV y el
server_write_IV son generados así solamente para ciphers
que no son exportables (los no exportables sólo pueden
usarse dentro de Estados Unidos y Canada).
Para los algoritmos de encriptación que sí son exportables, se
requiere un poco más de procesamiento para derivar sus final
write keys:
final_client_write_key | = PRF(SecurityParameters.client_write_key, "client write key",SecurityParameters.client_random + SecurityParameters.server_random) |
final_server_write_key | = PRF(SecurityParameters.server_write_key, "server write key", SecurityParameters.client_random + SecurityParameters.server_random) |
Además, los algoritmos exportables también inicializan los IVs aparte, con valores aleatorios que vienen de los mensajes hello. Se crea un vector de números aleatorios de forma similar a key_block:
iv_block | = PRF("", "IV block", SecurityParameters.client_random + SecurityParameters.server_random) |
Fíjese que la PRF se llama sin el secreto (""), lo que significa que el secreto no contribuye para nada en el resultado de la PRF (es decir, hay un "grado" menos de aletoriedad en el vector aleatorio generado).
Luego se particiona el iv_block en dos IVs de igual forma que arriba:
client_write_IV[SecurityParameters.IV_size]
server_write_IV[SecurityParameters.IV_size]