Q1. Why two sets of key material?
In section 8:3, they say that we create 2 MAC keys and 2 keys. Isn't that enough safe if the client and the server use the same key and MAC key ? (given that these key are generated from no less than a MasterSecret). I kind of think that it seem a bit overprotected..
No. This is done for a serious reason. This makes it actually harder to attack. There is a class of attack, where you just reflect what one side said back to itself. This is called a Reflection Attack. And by having direction fixed keys, you make that class of attack impossible.
Q2. How to chop up the key block?
When you have the MasterSecret, how do you expand it to create MAC keys and keys ? I doubt that we just take the first N bytes for the key and the rest for the MAC key
Sorry to disappoint you, but that's it actually. There is not much magic here.
You have the key block which is a long octet string. And then you simply chop it up into 6 smaller parts.
RFC
Here's the section in the TLS 1.2 RFC:
client_write_MAC_key[SecurityParameters.mac_key_length]
server_write_MAC_key[SecurityParameters.mac_key_length]
client_write_key[SecurityParameters.enc_key_length]
server_write_key[SecurityParameters.enc_key_length]
client_write_IV[SecurityParameters.fixed_iv_length]
server_write_IV[SecurityParameters.fixed_iv_length]
So that's six parts. And in that exact order. Odd entries (1, 3, 5) are for the client_write
direction. Even entries (2, 4, 6) are for the server_write
direction.
OpenSSL
Here's the chopping bit in OpenSSL:
This gets chopped up into:
ms
, MAC secret
key
, bulk encryption key
iv
, initialization vector
Source code from OpenSSL's t1_enc.c
:
if ((which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) ||
(which == SSL3_CHANGE_CIPHER_SERVER_READ)) {
ms = &(p[0]);
n = i + i;
key = &(p[n]);
n += j + j;
iv = &(p[n]);
n += k + k;
exp_label = (unsigned char *)TLS_MD_CLIENT_WRITE_KEY_CONST;
exp_label_len = TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE;
client_write = 1;
} else {
n = i;
ms = &(p[n]);
n += i + j;
key = &(p[n]);
n += j + k;
iv = &(p[n]);
n += k;
exp_label = (unsigned char *)TLS_MD_SERVER_WRITE_KEY_CONST;
exp_label_len = TLS_MD_SERVER_WRITE_KEY_CONST_SIZE;
client_write = 0;
}
I don't speak C too well. So I don't really get it.
- I don't understand the indexing into
p
.
- I don't understand why they only select one half of the keys. Each end needs both sets. One set to write to the other end. And one set read what the other end said. -- I guess that chopping happens elsewhere.