#include "ssl.h"
#ifndef _SSLREC_H_
#include "sslrec.h"
#endif
#ifndef _SSLALLOC_H_
#include "sslalloc.h"
#endif
#ifndef _CRYPTTYPE_H_
#include "cryptType.h"
#endif
#ifndef _SSLCTX_H_
#include "sslctx.h"
#endif
#ifndef _SSLALERT_H_
#include "sslalert.h"
#endif
#ifndef _SSL_DEBUG_H_
#include "sslDebug.h"
#endif
#ifndef _SSL2_H_
#include "ssl2.h"
#endif
#ifndef _SSLUTIL_H_
#include "sslutil.h"
#endif
#include "appleGlue.h"
#include <string.h>
#include <assert.h>
#define SSL_ALLOW_UNNOTICED_DISCONNECT 1
SSLErr
SSLReadRecord(SSLRecord *rec, SSLContext *ctx)
{ SSLErr err;
UInt32 len, contentLen;
UInt8 *progress;
SSLBuffer readData, cipherFragment;
if (!ctx->partialReadBuffer.data || ctx->partialReadBuffer.length < 5)
{ if (ctx->partialReadBuffer.data)
if ((err = SSLFreeBuffer(&ctx->partialReadBuffer, &ctx->sysCtx)) != 0)
{ SSLFatalSessionAlert(alert_close_notify, ctx);
return ERR(err);
}
if ((err = SSLAllocBuffer(&ctx->partialReadBuffer, DEFAULT_BUFFER_SIZE, &ctx->sysCtx)) != 0)
{ SSLFatalSessionAlert(alert_close_notify, ctx);
return ERR(err);
}
}
if (ctx->negProtocolVersion == SSL_Version_Undetermined ||
ctx->negProtocolVersion == SSL_Version_3_0_With_2_0_Hello)
if (ctx->amountRead < 1)
{ readData.length = 1 - ctx->amountRead;
readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
len = readData.length;
err = sslIoRead(readData, &len, ctx);
if(err != 0)
{ if (err == SSLWouldBlockErr)
ctx->amountRead += len;
else
SSLFatalSessionAlert(alert_close_notify, ctx);
return err;
}
ctx->amountRead += len;
}
switch (ctx->negProtocolVersion)
{ case SSL_Version_Undetermined:
case SSL_Version_3_0_With_2_0_Hello:
if (ctx->partialReadBuffer.data[0] < SSL_smallest_3_0_type ||
ctx->partialReadBuffer.data[0] > SSL_largest_3_0_type)
return SSL2ReadRecord(rec, ctx);
else
break;
case SSL_Version_2_0:
return SSL2ReadRecord(rec, ctx);
default:
break;
}
if (ctx->amountRead < 5)
{ readData.length = 5 - ctx->amountRead;
readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
len = readData.length;
err = sslIoRead(readData, &len, ctx);
if(err != 0)
{
switch(err) {
case SSLWouldBlockErr:
ctx->amountRead += len;
break;
#if SSL_ALLOW_UNNOTICED_DISCONNECT
case SSLConnectionClosedGraceful:
if((ctx->amountRead == 0) &&
(len == 0) &&
(ctx->state == HandshakeClientReady)) {
SSLChangeHdskState(ctx, SSLNoNotifyClose);
err = SSLConnectionClosedNoNotify;
break;
}
else {
err = SSLConnectionClosedError;
}
#endif
default:
SSLFatalSessionAlert(alert_close_notify, ctx);
break;
}
return err;
}
ctx->amountRead += len;
}
CASSERT(ctx->amountRead >= 5);
progress = ctx->partialReadBuffer.data;
rec->contentType = *progress++;
if (rec->contentType < SSL_smallest_3_0_type ||
rec->contentType > SSL_largest_3_0_type)
return ERR(SSLProtocolErr);
rec->protocolVersion = (SSLProtocolVersion)SSLDecodeInt(progress, 2);
progress += 2;
contentLen = SSLDecodeInt(progress, 2);
progress += 2;
if (contentLen > (16384 + 2048))
{ SSLFatalSessionAlert(alert_unexpected_message, ctx);
return ERR(SSLProtocolErr);
}
if (ctx->partialReadBuffer.length < 5 + contentLen)
{ if ((err = SSLReallocBuffer(&ctx->partialReadBuffer, 5 + contentLen, &ctx->sysCtx)) != 0)
{ SSLFatalSessionAlert(alert_close_notify, ctx);
return ERR(err);
}
}
if (ctx->amountRead < 5 + contentLen)
{ readData.length = 5 + contentLen - ctx->amountRead;
readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
len = readData.length;
err = sslIoRead(readData, &len, ctx);
if(err != 0)
{ if (err == SSLWouldBlockErr)
ctx->amountRead += len;
else
SSLFatalSessionAlert(alert_close_notify, ctx);
return err;
}
ctx->amountRead += len;
}
CASSERT(ctx->amountRead >= 5 + contentLen);
cipherFragment.data = ctx->partialReadBuffer.data + 5;
cipherFragment.length = contentLen;
assert(ctx->sslTslCalls != NULL);
if ((err = ctx->sslTslCalls->decryptRecord(rec->contentType,
&cipherFragment, ctx)) != 0)
return err;
IncrementUInt64(&ctx->readCipher.sequenceNum);
if ((err = SSLAllocBuffer(&rec->contents, cipherFragment.length, &ctx->sysCtx)) != 0)
{ SSLFatalSessionAlert(alert_close_notify, ctx);
return ERR(err);
}
memcpy(rec->contents.data, cipherFragment.data, cipherFragment.length);
ctx->amountRead = 0;
return SSLNoErr;
}
SSLErr SSLVerifyMac(
UInt8 type,
SSLBuffer data,
UInt8 *compareMAC,
SSLContext *ctx)
{
SSLErr err;
UInt8 macData[MAX_DIGEST_SIZE];
SSLBuffer secret, mac;
secret.data = ctx->readCipher.macSecret;
secret.length = ctx->readCipher.macRef->hash->digestSize;
mac.data = macData;
mac.length = ctx->readCipher.macRef->hash->digestSize;
assert(ctx->sslTslCalls != NULL);
if ((err = ctx->sslTslCalls->computeMac(type,
data,
mac,
&ctx->readCipher,
ctx->readCipher.sequenceNum,
ctx)) != 0)
return ERR(err);
if ((memcmp(mac.data, compareMAC, mac.length)) != 0) {
errorLog0("ssl3VerifyMac: Mac verify failure\n");
return ERR(SSLProtocolErr);
}
return SSLNoErr;
}