#include "sslMemory.h"
#include "tls_ssl.h"
#include "sslUtils.h"
#include "sslDigests.h"
#include "sslDebug.h"
#include "sslAlertMessage.h"
#include <assert.h>
#include <strings.h>
#include <stddef.h>
#define LOG_GEN_KEY 0
static OSStatus ssl3GenerateKeyMaterial (
SSLBuffer key, SSLContext *ctx)
{
OSStatus err;
UInt8 leaderData[10];
UInt8 shaHashData[20], md5HashData[16];
SSLBuffer shaContext, md5Context;
UInt8 *keyProgress;
size_t i,j,remaining, satisfied;
SSLBuffer leader, masterSecret, serverRandom, clientRandom, shaHash, md5Hash;
#if LOG_GEN_KEY
printf("GenerateKey: master ");
for(i=0; i<SSL_MASTER_SECRET_SIZE; i++) {
printf("%02X ", ctx->masterSecret[i]);
}
printf("\n");
#endif
assert(key.length <= 16 * sizeof(leaderData));
leader.data = leaderData;
masterSecret.data = ctx->masterSecret;
masterSecret.length = SSL_MASTER_SECRET_SIZE;
serverRandom.data = ctx->serverRandom;
serverRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
clientRandom.data = ctx->clientRandom;
clientRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
shaHash.data = shaHashData;
shaHash.length = 20;
md5Hash.data = md5HashData;
md5Hash.length = 16;
md5Context.data = 0;
shaContext.data = 0;
if ((err = ReadyHash(&SSLHashMD5, &md5Context)) != 0)
goto fail;
if ((err = ReadyHash(&SSLHashSHA1, &shaContext)) != 0)
goto fail;
keyProgress = key.data;
remaining = key.length;
for (i = 0; remaining > 0; ++i)
{ for (j = 0; j <= i; j++)
leaderData[j] = 0x41 + i;
leader.length = i+1;
if ((err = SSLHashSHA1.update(&shaContext, &leader)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&shaContext, &masterSecret)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&shaContext, &serverRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&shaContext, &clientRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.final(&shaContext, &shaHash)) != 0)
goto fail;
if ((err = SSLHashMD5.update(&md5Context, &masterSecret)) != 0)
goto fail;
if ((err = SSLHashMD5.update(&md5Context, &shaHash)) != 0)
goto fail;
if ((err = SSLHashMD5.final(&md5Context, &md5Hash)) != 0)
goto fail;
satisfied = 16;
if (remaining < 16)
satisfied = remaining;
memcpy(keyProgress, md5HashData, satisfied);
remaining -= satisfied;
keyProgress += satisfied;
if(remaining > 0) {
if ((err = SSLHashMD5.init(&md5Context)) != 0)
goto fail;
if ((err = SSLHashSHA1.init(&shaContext)) != 0)
goto fail;
}
}
assert(remaining == 0 && keyProgress == (key.data + key.length));
err = errSecSuccess;
fail:
SSLFreeBuffer(&md5Context);
SSLFreeBuffer(&shaContext);
#if LOG_GEN_KEY
printf("GenerateKey: DONE\n");
#endif
return err;
}
static OSStatus ssl3GenerateMasterSecret (
SSLContext *ctx)
{
OSStatus err;
SSLBuffer shaState, md5State, clientRandom,
serverRandom, shaHash, md5Hash, leader;
UInt8 *masterProgress, shaHashData[20], leaderData[3];
int i;
md5State.data = shaState.data = 0;
if ((err = SSLAllocBuffer(&md5State, SSLHashMD5.contextSize)))
goto fail;
if ((err = SSLAllocBuffer(&shaState, SSLHashSHA1.contextSize)))
goto fail;
clientRandom.data = ctx->clientRandom;
clientRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
serverRandom.data = ctx->serverRandom;
serverRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
shaHash.data = shaHashData;
shaHash.length = 20;
masterProgress = ctx->masterSecret;
for (i = 1; i <= 3; i++)
{ if ((err = SSLHashMD5.init(&md5State)) != 0)
goto fail;
if ((err = SSLHashSHA1.init(&shaState)) != 0)
goto fail;
leaderData[0] = leaderData[1] = leaderData[2] = 0x40 + i;
leader.data = leaderData;
leader.length = i;
if ((err = SSLHashSHA1.update(&shaState, &leader)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&shaState, &ctx->preMasterSecret)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&shaState, &clientRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&shaState, &serverRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.final(&shaState, &shaHash)) != 0)
goto fail;
if ((err = SSLHashMD5.update(&md5State, &ctx->preMasterSecret)) != 0)
goto fail;
if ((err = SSLHashMD5.update(&md5State, &shaHash)) != 0)
goto fail;
md5Hash.data = masterProgress;
md5Hash.length = 16;
if ((err = SSLHashMD5.final(&md5State, &md5Hash)) != 0)
goto fail;
masterProgress += 16;
}
err = errSecSuccess;
fail:
SSLFreeBuffer(&shaState);
SSLFreeBuffer(&md5State);
return err;
}
static OSStatus
ssl3CalculateFinishedMessage(
SSLContext *ctx,
SSLBuffer finished, SSLBuffer shaMsgState, SSLBuffer md5MsgState, UInt32 senderID) {
OSStatus err;
SSLBuffer hash, input;
UInt8 sender[4], md5Inner[16], shaInner[20];
if (senderID != 0) {
SSLEncodeInt(sender, senderID, 4);
input.data = sender;
input.length = 4;
if ((err = SSLHashMD5.update(&md5MsgState, &input)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&shaMsgState, &input)) != 0)
goto fail;
}
input.data = ctx->masterSecret;
input.length = SSL_MASTER_SECRET_SIZE;
if ((err = SSLHashMD5.update(&md5MsgState, &input)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&shaMsgState, &input)) != 0)
goto fail;
input.data = (UInt8 *)SSLMACPad1;
input.length = SSLHashMD5.macPadSize;
if ((err = SSLHashMD5.update(&md5MsgState, &input)) != 0)
goto fail;
input.length = SSLHashSHA1.macPadSize;
if ((err = SSLHashSHA1.update(&shaMsgState, &input)) != 0)
goto fail;
hash.data = md5Inner;
hash.length = 16;
if ((err = SSLHashMD5.final(&md5MsgState, &hash)) != 0)
goto fail;
hash.data = shaInner;
hash.length = 20;
if ((err = SSLHashSHA1.final(&shaMsgState, &hash)) != 0)
goto fail;
if ((err = SSLHashMD5.init(&md5MsgState)) != 0)
goto fail;
if ((err = SSLHashSHA1.init(&shaMsgState)) != 0)
goto fail;
input.data = ctx->masterSecret;
input.length = SSL_MASTER_SECRET_SIZE;
if ((err = SSLHashMD5.update(&md5MsgState, &input)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&shaMsgState, &input)) != 0)
goto fail;
input.data = (UInt8 *)SSLMACPad2;
input.length = SSLHashMD5.macPadSize;
if ((err = SSLHashMD5.update(&md5MsgState, &input)) != 0)
goto fail;
input.length = SSLHashSHA1.macPadSize;
if ((err = SSLHashSHA1.update(&shaMsgState, &input)) != 0)
goto fail;
input.data = md5Inner;
input.length = 16;
if ((err = SSLHashMD5.update(&md5MsgState, &input)) != 0)
goto fail;
hash.data = finished.data;
hash.length = 16;
if ((err = SSLHashMD5.final(&md5MsgState, &hash)) != 0)
goto fail;
input.data = shaInner;
input.length = 20;
if ((err = SSLHashSHA1.update(&shaMsgState, &input)) != 0)
goto fail;
hash.data = finished.data + 16;
hash.length = 20;
if ((err = SSLHashSHA1.final(&shaMsgState, &hash)) != 0)
goto fail;
fail:
return err;
}
static OSStatus ssl3ComputeFinishedMac (
SSLContext *ctx,
SSLBuffer finished, Boolean isServer) {
OSStatus serr;
SSLBuffer shaMsgState, md5MsgState;
shaMsgState.data = 0;
md5MsgState.data = 0;
if ((serr = CloneHashState(&SSLHashSHA1, &ctx->shaState, &shaMsgState)) != 0)
goto fail;
if ((serr = CloneHashState(&SSLHashMD5, &ctx->md5State, &md5MsgState)) != 0)
goto fail;
serr = ssl3CalculateFinishedMessage(ctx, finished, shaMsgState, md5MsgState,
isServer ? SSL_Finished_Sender_Server : SSL_Finished_Sender_Client);
fail:
SSLFreeBuffer(&shaMsgState);
SSLFreeBuffer(&md5MsgState);
return serr;
}
static OSStatus ssl3ComputeCertVfyMac (
SSLContext *ctx,
SSLBuffer *finished, SSL_HashAlgorithm hash) {
OSStatus serr;
SSLBuffer shaMsgState, md5MsgState;
shaMsgState.data = 0;
md5MsgState.data = 0;
if ((serr = CloneHashState(&SSLHashSHA1, &ctx->shaState, &shaMsgState)) != 0)
goto fail;
if ((serr = CloneHashState(&SSLHashMD5, &ctx->md5State, &md5MsgState)) != 0)
goto fail;
assert(finished->length >= SSL_MD5_DIGEST_LEN + SSL_SHA1_DIGEST_LEN);
finished->length = SSL_MD5_DIGEST_LEN + SSL_SHA1_DIGEST_LEN;
serr = ssl3CalculateFinishedMessage(ctx, *finished, shaMsgState, md5MsgState, 0);
fail:
SSLFreeBuffer(&shaMsgState);
SSLFreeBuffer(&md5MsgState);
return serr;
}
const SslTlsCallouts Ssl3Callouts = {
ssl3GenerateKeyMaterial,
ssl3GenerateMasterSecret,
ssl3ComputeFinishedMac,
ssl3ComputeCertVfyMac
};