The pre-master secret is encrypted and exchanged in the TLS handshake. This value is used to derive the master key. The master key is used to derive all other keying material by passing it into a pseudo-random function (PRF), and combining other pieces of data from the handshake.
Deriving the Pre-Master Secret for a PSK
From RFC427: Section 2
The premaster secret is formed as follows: if the PSK is N octets long, concatenate a
uint16 with the value N, N zero octets, a second
uint16 with the value N, and the PSK itself.
If using Diffie Hellman w/ PSK, Section 3:
The premaster secret is formed as follows. First, perform the Diffie-Hellman computation in the same way as for other Diffie-Hellman-based ciphersuites in [TLS]. Let Z be the value produced by this computation (with leading zero bytes stripped as in other Diffie-Hellman-based ciphersuites). Concatenate a
uint16 containing the length of Z (in octets), Z itself, a
uint16 containing the length of the PSK (in octets), and the PSK itself.
If using RSA w/ PSK, Section 4
The EncryptedPreMasterSecret field sent from the client to the server contains a 2-byte version number and a 46-byte random value, encrypted using the server's RSA public key as described in Section 126.96.36.199 of [TLS]. The actual premaster secret is formed by both parties as follows: concatenate a uint16 with the value 48, the 2-byte version number and the 46-byte random value, a uint16 containing the length of the PSK (in octets), and the PSK itself. (The premaster secret is thus 52 octets longer than the PSK.)
Deriving Master Key
Everything that follows does not just apply to TLS PSK; it applies to all key exchange types. From RFC 2246: Section 8.1
For all key exchange methods, the same algorithm is used to convert the pre_master_secret into the master_secret. The pre_master_secret should be deleted from memory once the master_secret has been computed. The master secret is always exactly 48 bytes in length. The length of the premaster secret will vary depending on key exchange method.
master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random)
The PRF is defined as combining two different hashing functions. Section 5 of RFC 2246:
First, we define a data expansion function, P_hash(secret, data) which uses a single hash function to expand a secret and seed into an arbitrary quantity of output:
P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
HMAC_hash(secret, A(2) + seed) +
HMAC_hash(secret, A(3) + seed) + ...
Where + indicates concatenation.
A() is defined as:
A(0) = seed
A(i) = HMAC_hash(secret, A(i-1))
The function described above is really
P_SHA1. The TLS PRF is described as follows:
TLS's PRF is created by splitting the secret into two halves and using one half to generate data with P_MD5 and the other half to generate data with P_SHA-1, then exclusive-or'ing (XOR) the outputs of these two expansion functions together.
So lets claim the following:
L_S = length in bytes of secret;
L_S1 = L_S2 = ceil(L_S / 2);
The PRF is then:
PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
P_SHA-1(S2, label + seed);
Derive Encryption Keys
The key derivation is described in RFC 2246: Section 6.3
The entire keyblock is derived as follows:
key_block = PRF(SecurityParameters.master_secret,
Once enough material is generated and stored in the
key_block is split into the encryption/decryption keys. Encryption or decryption depends on the direction. As they're all referenced as write keys. The
key_block is sequentially split into the arrays:
There's some additional computations performed for exportable block ciphers. You can read those details in Section 6.3 of RFC2246 as well. Section 6.3.1 gives an example of these computations without the extra descriptions.