#include "ssl.h"
#include "sslRecord.h"
#include "sslMemory.h"
#include "cryptType.h"
#include "sslContext.h"
#include "sslAlertMessage.h"
#include "sslDebug.h"
#include "ssl2.h"
#include "sslUtils.h"
#include "sslDigests.h"
#include <string.h>
#include <assert.h>
#define SSL_ALLOW_UNNOTICED_DISCONNECT 1
OSStatus
SSLReadRecord(SSLRecord &rec, SSLContext *ctx)
{ OSStatus err;
UInt32 len, contentLen;
UInt8 *charPtr;
SSLBuffer readData, cipherFragment;
if (!ctx->partialReadBuffer.data || ctx->partialReadBuffer.length < 5)
{ if (ctx->partialReadBuffer.data)
if ((err = SSLFreeBuffer(ctx->partialReadBuffer, ctx)) != 0)
{ SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
return err;
}
if ((err = SSLAllocBuffer(ctx->partialReadBuffer,
DEFAULT_BUFFER_SIZE, ctx)) != 0)
{ SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
return err;
}
}
if (ctx->negProtocolVersion == SSL_Version_Undetermined) {
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 == errSSLWouldBlock) {
ctx->amountRead += len;
return err;
}
else {
SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx);
return errSSLClosedAbort;
}
}
ctx->amountRead += len;
}
}
switch (ctx->negProtocolVersion)
{ case SSL_Version_Undetermined:
if (ctx->partialReadBuffer.data[0] < SSL_RecordTypeV3_Smallest ||
ctx->partialReadBuffer.data[0] > SSL_RecordTypeV3_Largest)
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 errSSLWouldBlock:
ctx->amountRead += len;
break;
#if SSL_ALLOW_UNNOTICED_DISCONNECT
case errSSLClosedGraceful:
if((ctx->amountRead == 0) &&
(len == 0) &&
(ctx->state == SSL_HdskStateClientReady)) {
SSLChangeHdskState(ctx, SSL_HdskStateNoNotifyClose);
err = errSSLClosedNoNotify;
break;
}
else {
err = errSSLClosedAbort;
}
#endif
default:
SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx);
break;
}
return err;
}
ctx->amountRead += len;
}
assert(ctx->amountRead >= 5);
charPtr = ctx->partialReadBuffer.data;
rec.contentType = *charPtr++;
if (rec.contentType < SSL_RecordTypeV3_Smallest ||
rec.contentType > SSL_RecordTypeV3_Largest)
return errSSLProtocol;
rec.protocolVersion = (SSLProtocolVersion)SSLDecodeInt(charPtr, 2);
charPtr += 2;
contentLen = SSLDecodeInt(charPtr, 2);
charPtr += 2;
if (contentLen > (16384 + 2048))
{ SSLFatalSessionAlert(SSL_AlertRecordOverflow, ctx);
return errSSLProtocol;
}
if (ctx->partialReadBuffer.length < 5 + contentLen)
{ if ((err = SSLReallocBuffer(ctx->partialReadBuffer, 5 + contentLen, ctx)) != 0)
{ SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
return 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 == errSSLWouldBlock)
ctx->amountRead += len;
else
SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx);
return err;
}
ctx->amountRead += len;
}
assert(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)) != 0)
{ SSLFatalSessionAlert(SSL_AlertInternalError, ctx);
return err;
}
memcpy(rec.contents.data, cipherFragment.data, cipherFragment.length);
ctx->amountRead = 0;
return noErr;
}
OSStatus SSLVerifyMac(
UInt8 type,
SSLBuffer &data,
UInt8 *compareMAC,
SSLContext *ctx)
{
OSStatus err;
UInt8 macData[SSL_MAX_DIGEST_LEN];
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;
if ((memcmp(mac.data, compareMAC, mac.length)) != 0) {
sslErrorLog("ssl3VerifyMac: Mac verify failure\n");
return errSSLProtocol;
}
return noErr;
}