Finish Messages in the TLS 1.0 Protocol

A finish message is sent immediately after a change cipher spec message to verify the success of key exchange and authentication processes. The finish messages in the TLS 1.0 protocol are calculated using Pseudo-Random Function (PRF) with the master key, a label, and a seed as input. PRF 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 set to CALG_TLS1PRF and the handle to the master key 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 calls 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 PRF 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 following is typical source code for this protocol engine:

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);