sslAlertMessage.cpp [plain text]
#include "ssl.h"
#include "sslAlertMessage.h"
#include "sslMemory.h"
#include "sslContext.h"
#include "sslSession.h"
#include "sslDebug.h"
#include "sslUtils.h"
#include <assert.h>
#ifdef NDEBUG
#define SSLLogAlertMsg(msg,sent)
#else
static void SSLLogAlertMsg(AlertDescription msg, bool sent);
#endif
static OSStatus SSLEncodeAlert(
SSLRecord &rec,
AlertLevel level,
AlertDescription desc,
SSLContext *ctx);
static void
SSLDetectCertRejected(
SSLContext *ctx,
AlertDescription desc)
{
if(ctx->protocolSide == SSL_ServerSide) {
return;
}
if(ctx->clientCertState != kSSLClientCertSent) {
return;
}
switch(desc) {
case SSL_AlertBadCert:
case SSL_AlertUnsupportedCert:
case SSL_AlertCertRevoked:
case SSL_AlertCertExpired:
case SSL_AlertCertUnknown:
case SSL_AlertUnknownCA:
ctx->clientCertState = kSSLClientCertRejected;
break;
default:
break;
}
}
OSStatus
SSLProcessAlert(SSLRecord rec, SSLContext *ctx)
{ OSStatus err = noErr;
AlertLevel level;
AlertDescription desc;
uint8 *charPtr;
uint32 remaining;
if (rec.contents.length % 2 != 0)
{
err = SSLFatalSessionAlert(SSL_AlertIllegalParam, ctx);
if (!err) {
err = errSSLProtocol;
}
return err;
}
charPtr = rec.contents.data;
remaining = rec.contents.length;
bool fatal = false;
while (remaining > 0)
{ level = (AlertLevel)*charPtr++;
desc = (AlertDescription)*charPtr++;
sslHdskMsgDebug("alert msg recieved level %d desc %d",
(int)level, (int)desc);
remaining -= 2;
SSLLogAlertMsg(desc, false);
if (level == SSL_AlertLevelFatal) {
fatal = true;
sslHdskMsgDebug("***Fatal alert %d received\n", desc);
}
SSLDetectCertRejected(ctx, desc);
switch (desc) {
case SSL_AlertUnexpectedMsg:
err = errSSLPeerUnexpectedMsg;
fatal = true;
break;
case SSL_AlertBadRecordMac:
err = errSSLPeerBadRecordMac;
fatal = true;
break;
case SSL_AlertDecryptionFail:
err = errSSLPeerDecryptionFail;
fatal = true;
break;
case SSL_AlertRecordOverflow:
err = errSSLPeerRecordOverflow;
fatal = true;
break;
case SSL_AlertDecompressFail:
err = errSSLPeerDecompressFail;
fatal = true;
break;
case SSL_AlertHandshakeFail:
err = errSSLPeerHandshakeFail;
fatal = true;
break;
case SSL_AlertIllegalParam:
err = errSSLIllegalParam;
fatal = true;
break;
case SSL_AlertBadCert:
err = errSSLPeerBadCert;
break;
case SSL_AlertUnsupportedCert:
err = errSSLPeerUnsupportedCert;
break;
case SSL_AlertCertRevoked:
err = errSSLPeerCertRevoked;
break;
case SSL_AlertCertExpired:
err = errSSLPeerCertExpired;
break;
case SSL_AlertCertUnknown:
err = errSSLPeerCertUnknown;
break;
case SSL_AlertUnknownCA:
err = errSSLPeerUnknownCA;
break;
case SSL_AlertAccessDenied:
err = errSSLPeerAccessDenied;
break;
case SSL_AlertDecodeError:
err = errSSLPeerDecodeError;
break;
case SSL_AlertDecryptError:
err = errSSLPeerDecryptError;
break;
case SSL_AlertExportRestriction:
err = errSSLPeerExportRestriction;
break;
case SSL_AlertProtocolVersion:
err = errSSLPeerProtocolVersion;
break;
case SSL_AlertInsufficientSecurity:
err = errSSLPeerInsufficientSecurity;
break;
case SSL_AlertInternalError:
err = errSSLPeerInternalError;
break;
case SSL_AlertUserCancelled:
err = errSSLPeerUserCancelled;
break;
case SSL_AlertNoRenegotiation:
err = errSSLPeerNoRenegotiation;
break;
case SSL_AlertCloseNotify:
SSLClose(ctx);
err = noErr;
break;
case SSL_AlertNoCert:
if((ctx->state == SSL_HdskStateClientCert) &&
(ctx->protocolSide == SSL_ServerSide) &&
(ctx->clientAuth != kAlwaysAuthenticate)) {
if ((err = SSLAdvanceHandshake(SSL_HdskCert,
ctx)) != 0) {
return err;
}
}
break;
default:
if(level == SSL_AlertLevelFatal) {
err = errSSLFatalAlert;
}
else {
err = noErr;
}
break;
}
if(fatal) {
break;
}
}
if(fatal) {
SSLDeleteSessionData(ctx);
}
return err;
}
OSStatus
SSLSendAlert(AlertLevel level, AlertDescription desc, SSLContext *ctx)
{ SSLRecord rec;
OSStatus err;
switch(ctx->negProtocolVersion) {
case SSL_Version_Undetermined:
return noErr;
case SSL_Version_2_0:
assert(0);
return errSSLInternal;
default:
break;
}
if(ctx->sentFatalAlert) {
return noErr;
}
if ((err = SSLEncodeAlert(rec, level, desc, ctx)) != 0)
return err;
assert(ctx->sslTslCalls != NULL);
SSLLogAlertMsg(desc, true);
if ((err = ctx->sslTslCalls->writeRecord(rec, ctx)) != 0)
return err;
if ((err = SSLFreeBuffer(rec.contents, ctx)) != 0)
return err;
if(desc == SSL_AlertCloseNotify) {
ctx->sentFatalAlert = true;
}
return noErr;
}
static OSStatus
SSLEncodeAlert(SSLRecord &rec, AlertLevel level, AlertDescription desc, SSLContext *ctx)
{ OSStatus err;
rec.protocolVersion = ctx->negProtocolVersion;
rec.contentType = SSL_RecordTypeAlert;
rec.contents.length = 2;
if ((err = SSLAllocBuffer(rec.contents, 2, ctx)) != 0)
return err;
rec.contents.data[0] = level;
rec.contents.data[1] = desc;
return noErr;
}
OSStatus
SSLFatalSessionAlert(AlertDescription desc, SSLContext *ctx)
{ OSStatus err1, err2;
if(desc != SSL_AlertCloseNotify) {
sslHdskMsgDebug("SSLFatalSessionAlert: desc %d\n", desc);
}
SSLChangeHdskState(ctx, SSL_HdskStateErrorClose);
if(ctx->negProtocolVersion < TLS_Version_1_0) {
switch(desc) {
case SSL_AlertDecryptionFail:
case SSL_AlertRecordOverflow:
case SSL_AlertAccessDenied:
case SSL_AlertDecodeError:
case SSL_AlertDecryptError:
case SSL_AlertExportRestriction:
case SSL_AlertProtocolVersion:
case SSL_AlertInsufficientSecurity:
case SSL_AlertUserCancelled:
case SSL_AlertNoRenegotiation:
desc = SSL_AlertHandshakeFail;
break;
case SSL_AlertUnknownCA:
desc = SSL_AlertUnsupportedCert;
break;
case SSL_AlertInternalError:
desc = SSL_AlertCloseNotify;
break;
default:
break;
}
}
err1 = SSLDeleteSessionData(ctx);
err2 = SSLSendAlert(SSL_AlertLevelFatal, desc, ctx);
ctx->sentFatalAlert = true;
return err1 != 0 ? err1 : err2;
}
#ifndef NDEBUG
static char *alertMsgToStr(AlertDescription msg)
{
static char badStr[100];
switch(msg) {
case SSL_AlertCloseNotify:
return "SSL_AlertCloseNotify";
case SSL_AlertUnexpectedMsg:
return "SSL_AlertUnexpectedMsg";
case SSL_AlertBadRecordMac:
return "SSL_AlertBadRecordMac";
case SSL_AlertDecryptionFail:
return "SSL_AlertDecryptionFail";
case SSL_AlertRecordOverflow:
return "SSL_AlertRecordOverflow";
case SSL_AlertDecompressFail:
return "SSL_AlertDecompressFail";
case SSL_AlertHandshakeFail:
return "SSL_AlertHandshakeFail";
case SSL_AlertNoCert:
return "SSL_AlertNoCert";
case SSL_AlertBadCert:
return "SSL_AlertBadCert";
case SSL_AlertUnsupportedCert:
return "SSL_AlertUnsupportedCert";
case SSL_AlertCertRevoked:
return "SSL_AlertCertRevoked";
case SSL_AlertCertExpired:
return "SSL_AlertCertExpired";
case SSL_AlertCertUnknown:
return "SSL_AlertCertUnknown";
case SSL_AlertIllegalParam:
return "SSL_AlertIllegalParam";
case SSL_AlertUnknownCA:
return "SSL_AlertUnknownCA";
case SSL_AlertAccessDenied:
return "SSL_AlertAccessDenied";
case SSL_AlertDecodeError:
return "SSL_AlertDecodeError";
case SSL_AlertDecryptError:
return "SSL_AlertDecryptError";
case SSL_AlertExportRestriction:
return "SSL_AlertExportRestriction";
case SSL_AlertProtocolVersion:
return "SSL_AlertProtocolVersion";
case SSL_AlertInsufficientSecurity:
return "SSL_AlertInsufficientSecurity";
case SSL_AlertInternalError:
return "SSL_AlertInternalError";
case SSL_AlertUserCancelled:
return "SSL_AlertUserCancelled";
case SSL_AlertNoRenegotiation:
return "SSL_AlertNoRenegotiation";
default:
sprintf(badStr, "Unknown state (%d(d)", msg);
return badStr;
}
}
static void SSLLogAlertMsg(AlertDescription msg, bool sent)
{
sslHdskMsgDebug("---%s alert msg %s",
alertMsgToStr(msg), (sent ? "sent" : "recv"));
}
#endif