A "finished" message is always sent immediately after a "change cipher spec" message to verify that the key exchange and authentication processes were successful. The "finish" messages in the TLS 1.0 protocol are calculated using the Pseudo-Random Function (PRF) function with the input being the master key, a label, and a seed. The PRF uses the key, the label, and the seed as input and produces an output of arbitrary length. The following method is used to generate the PRF output used in TLS 1.0 "finish" messages.
A PRF hash handle is generated using CryptCreateHash with the ALG_ID value CALG_TLS1PRF and the handle to the master key is passed in the hKey parameter. The label and seed values are set on the hash handle using the values HP_TLS1PRF_LABEL and HP_TLS1PRF_SEED respectively in the dwParam parameter with the CryptSetHashParam function. Finally the protocol engine will call the function CryptGetHashParam with the value HP_HASHVAL in the dwParam parameter to retrieve the PRF data to be included in the finish message. When making the call to CryptGetHashParam, the protocol engine must specify how many bytes of data that the PRF function will produce. This is done in the pdwDataLen parameter, and the resulting data is placed in the buffer pointed to by the pbData parameter.
The protocol engine's source code is typically;
CRYPT_DATA_BLOB Data;
HCRYPTHASH hFinishHash;
BYTE rgbFinishPRF[12];
BYTE rgbCliHashOfHandshakes[36];
// get client finish message
CryptCreateHash(hProv, CALG_TLS1PRF, hMasterKey, 0, &hFinishHash);
Data.pbData = (BYTE*)"client finished";
Data.cbData = 15;
CryptSetHashParam(hFinishHash, HP_TLS1PRF_LABEL, (BYTE*)&Data, 0);
Data.pbData = rgbCliHashOfHandshakes;
Data.cbData = sizeof(rgbCliHashOfHandshakes);
CryptSetHashParam(hFinishHash, HP_TLS1PRF_SEED, (BYTE*)&Data, 0);
cbFinishPRF = sizeof(rgbFinishPRF);
CryptGetHashParam(hFinishHash, HP_HASHVAL, rgbFinishPRF, &cbFinishPRF, 0);
CryptDestroyHash(hFinishHash);