#ifndef _SSLCTX_H_
#include "sslctx.h"
#endif
#ifndef _SSLHDSHK_H_
#include "sslhdshk.h"
#endif
#ifndef _SSLALLOC_H_
#include "sslalloc.h"
#endif
#ifndef _SSLALERT_H_
#include "sslalert.h"
#endif
#ifndef _SSLSESS_H_
#include "sslsess.h"
#endif
#ifndef _SSLUTIL_H_
#include "sslutil.h"
#endif
#ifndef _SSL_DEBUG_H_
#include "sslDebug.h"
#endif
#ifndef _APPLE_CDSA_H_
#include "appleCdsa.h"
#endif
#include "digests.h"
#include <string.h>
#include <assert.h>
#define REQUEST_CERT_CORRECT 0
static SSLErr SSLProcessHandshakeMessage(SSLHandshakeMsg message, SSLContext *ctx);
SSLErr
SSLProcessHandshakeRecord(SSLRecord rec, SSLContext *ctx)
{ SSLErr err;
sint32 remaining;
UInt8 *p;
SSLHandshakeMsg message;
SSLBuffer messageData;
if (ctx->fragmentedMessageCache.data != 0)
{ if ((err = SSLReallocBuffer(&ctx->fragmentedMessageCache,
ctx->fragmentedMessageCache.length + rec.contents.length,
&ctx->sysCtx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return ERR(err);
}
memcpy(ctx->fragmentedMessageCache.data + ctx->fragmentedMessageCache.length,
rec.contents.data, rec.contents.length);
remaining = ctx->fragmentedMessageCache.length;
p = ctx->fragmentedMessageCache.data;
}
else
{ remaining = rec.contents.length;
p = rec.contents.data;
}
while (remaining > 0)
{ if (remaining < 4)
break;
messageData.data = p;
message.type = (SSLHandshakeType)*p++;
message.contents.length = SSLDecodeInt(p, 3);
if ((message.contents.length + 4) > remaining)
break;
p += 3;
message.contents.data = p;
p += message.contents.length;
messageData.length = 4 + message.contents.length;
CASSERT(p == messageData.data + messageData.length);
remaining -= messageData.length;
if (ERR(err = SSLProcessHandshakeMessage(message, ctx)) != 0)
return err;
if (message.type != SSL_hello_request)
{ if (ERR(err = SSLHashSHA1.update(ctx->shaState, messageData)) != 0 ||
ERR(err = SSLHashMD5.update(ctx->md5State, messageData)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
}
if (ERR(err = SSLAdvanceHandshake(message.type, ctx)) != 0)
return err;
}
if (remaining > 0)
{
if (ctx->fragmentedMessageCache.data == 0)
{ if (ERR(err = SSLAllocBuffer(&ctx->fragmentedMessageCache, remaining, &ctx->sysCtx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
}
if (p != ctx->fragmentedMessageCache.data)
{ memcpy(ctx->fragmentedMessageCache.data, p, remaining);
ctx->fragmentedMessageCache.length = remaining;
}
}
else if (ctx->fragmentedMessageCache.data != 0)
{ if (ERR(err = SSLFreeBuffer(&ctx->fragmentedMessageCache, &ctx->sysCtx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
}
return SSLNoErr;
}
static SSLErr
SSLProcessHandshakeMessage(SSLHandshakeMsg message, SSLContext *ctx)
{ SSLErr err;
err = SSLNoErr;
SSLLogHdskMsg(message.type, 0);
switch (message.type)
{ case SSL_hello_request:
if (ctx->protocolSide != SSL_ClientSide)
goto wrongMessage;
if (message.contents.length > 0)
err = ERR(SSLProtocolErr);
break;
case SSL_client_hello:
if (ctx->state != HandshakeServerUninit)
goto wrongMessage;
ERR(err = SSLProcessClientHello(message.contents, ctx));
break;
case SSL_server_hello:
if (ctx->state != HandshakeServerHello &&
ctx->state != HandshakeServerHelloUnknownVersion)
goto wrongMessage;
ERR(err = SSLProcessServerHello(message.contents, ctx));
break;
case SSL_certificate:
if (ctx->state != HandshakeCertificate &&
ctx->state != HandshakeClientCertificate)
goto wrongMessage;
ERR(err = SSLProcessCertificate(message.contents, ctx));
break;
case SSL_certificate_request:
if ((ctx->state != HandshakeHelloDone && ctx->state != HandshakeKeyExchange)
|| ctx->certRequested)
goto wrongMessage;
ERR(err = SSLProcessCertificateRequest(message.contents, ctx));
break;
case SSL_server_key_exchange:
switch(ctx->state) {
case HandshakeKeyExchange:
case HandshakeHelloDone:
break;
default:
goto wrongMessage;
}
ERR(err = SSLProcessServerKeyExchange(message.contents, ctx));
break;
case SSL_server_hello_done:
if (ctx->state != HandshakeHelloDone)
goto wrongMessage;
ERR(err = SSLProcessServerHelloDone(message.contents, ctx));
break;
case SSL_certificate_verify:
if (ctx->state != HandshakeClientCertVerify)
goto wrongMessage;
ERR(err = SSLProcessCertificateVerify(message.contents, ctx));
break;
case SSL_client_key_exchange:
if (ctx->state != HandshakeClientKeyExchange)
goto wrongMessage;
ERR(err = SSLProcessKeyExchange(message.contents, ctx));
break;
case SSL_finished:
if (ctx->state != HandshakeFinished)
goto wrongMessage;
ERR(err = SSLProcessFinished(message.contents, ctx));
break;
default:
goto wrongMessage;
break;
}
if (err)
{ if (err == SSLProtocolErr)
ERR(SSLFatalSessionAlert(alert_illegal_parameter, ctx));
else if (err == SSLNegotiationErr)
ERR(SSLFatalSessionAlert(alert_handshake_failure, ctx));
else
ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
}
return ERR(err);
wrongMessage:
ERR(SSLFatalSessionAlert(alert_unexpected_message, ctx));
return ERR(SSLProtocolErr);
}
SSLErr
SSLAdvanceHandshake(SSLHandshakeType processed, SSLContext *ctx)
{ SSLErr err;
SSLBuffer sessionIdentifier;
switch (processed)
{ case SSL_hello_request:
if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeClientHello, ctx)) != 0)
return err;
SSLChangeHdskState(ctx, HandshakeServerHello);
break;
case SSL_client_hello:
CASSERT(ctx->protocolSide == SSL_ServerSide);
if (ctx->sessionID.data != 0)
{ if (ctx->resumableSession.data != 0)
{ if (ERR(err = SSLRetrieveSessionID(ctx->resumableSession, &sessionIdentifier, ctx)) != 0)
return err;
if (sessionIdentifier.length == ctx->sessionID.length &&
memcmp(sessionIdentifier.data, ctx->sessionID.data, ctx->sessionID.length) == 0)
{
SSLLogResumSess("===RESUMING SSL3 server-side session\n");
if (ERR(err = SSLInstallSessionFromData(ctx->resumableSession,
ctx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeServerHello, ctx)) != 0)
return err;
if (ERR(err = SSLInitPendingCiphers(ctx)) != 0 ||
ERR(err = SSLFreeBuffer(&sessionIdentifier, &ctx->sysCtx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeChangeCipherSpec, ctx)) != 0)
return err;
if (ERR(err = SSLDisposeCipherSuite(&ctx->writeCipher, ctx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
ctx->writeCipher = ctx->writePending;
ctx->writeCipher.ready = 0;
memset(&ctx->writePending, 0, sizeof(CipherContext));
if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeFinishedMessage, ctx)) != 0)
return err;
ctx->writeCipher.ready = 1;
SSLChangeHdskState(ctx, HandshakeChangeCipherSpec);
break;
}
else {
SSLLogResumSess(
"===FAILED TO RESUME SSL3 server-side session\n");
}
if (ERR(err = SSLFreeBuffer(&sessionIdentifier, &ctx->sysCtx)) != 0 ||
ERR(err = SSLDeleteSessionData(ctx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
}
if (ERR(err = SSLFreeBuffer(&ctx->sessionID, &ctx->sysCtx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
}
if (ctx->peerID.data != 0)
{
CASSERT(ctx->sessionID.data == 0);
ERR(err = SSLAllocBuffer(&ctx->sessionID, SSL_SESSION_ID_LEN, &ctx->sysCtx));
if (err == 0)
{
if((err = sslRand(ctx, &ctx->sessionID)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
}
}
if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeServerHello, ctx)) != 0)
return err;
switch (ctx->selectedCipherSpec->keyExchangeMethod)
{ case SSL_NULL_auth:
#if APPLE_DH
case SSL_DH_anon:
#endif
case SSL_DH_anon_EXPORT:
#if ST_SERVER_MODE_ENABLE
if(ctx->clientAuth == kAlwaysAuthenticate) {
SSLFatalSessionAlert(alert_handshake_failure, ctx);
return SSLNegotiationErr;
}
ctx->tryClientAuth = false;
#else
#endif
break;
default:
if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeCertificate, ctx)) != 0)
return err;
break;
}
#if SSL_SERVER_KEYEXCH_HACK
if((ctx->selectedCipherSpec->keyExchangeMethod != SSL_RSA) &&
(ctx->encryptPrivKey != NULL)) {
err = SSLPrepareAndQueueMessage(SSLEncodeServerKeyExchange, ctx);
if(err) {
return err;
}
}
#else
if (ctx->encryptPrivKey != NULL) {
err = SSLPrepareAndQueueMessage(SSLEncodeServerKeyExchange, ctx);
if(err) {
return err;
}
}
#endif
#if ST_SERVER_MODE_ENABLE
if (ctx->tryClientAuth)
{ if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeCertificateRequest, ctx)) != 0)
return err;
ctx->certRequested = 1;
}
#else
#endif
if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeServerHelloDone, ctx)) != 0)
return err;
if (ctx->certRequested) {
SSLChangeHdskState(ctx, HandshakeClientCertificate);
}
else {
SSLChangeHdskState(ctx, HandshakeClientKeyExchange);
}
break;
case SSL_server_hello:
if (ctx->resumableSession.data != 0 && ctx->sessionID.data != 0)
{ if (ERR(err = SSLRetrieveSessionID(ctx->resumableSession, &sessionIdentifier, ctx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
if (sessionIdentifier.length == ctx->sessionID.length &&
memcmp(sessionIdentifier.data, ctx->sessionID.data, ctx->sessionID.length) == 0)
{
SSLLogResumSess("===RESUMING SSL3 client-side session\n");
if (ERR(err = SSLInstallSessionFromData(ctx->resumableSession,
ctx)) != 0 ||
ERR(err = SSLInitPendingCiphers(ctx)) != 0 ||
ERR(err = SSLFreeBuffer(&sessionIdentifier, &ctx->sysCtx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
SSLChangeHdskState(ctx, HandshakeChangeCipherSpec);
break;
}
else {
SSLLogResumSess("===FAILED TO RESUME SSL3 client-side session\n");
}
if (ERR(err = SSLFreeBuffer(&sessionIdentifier, &ctx->sysCtx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
}
switch (ctx->selectedCipherSpec->keyExchangeMethod)
{
case SSL_NULL_auth:
case SSL_DH_anon:
case SSL_DH_anon_EXPORT:
SSLChangeHdskState(ctx, HandshakeKeyExchange);
break;
case SSL_RSA:
case SSL_DH_DSS:
case SSL_DH_DSS_EXPORT:
case SSL_DH_RSA:
case SSL_DH_RSA_EXPORT:
case SSL_RSA_EXPORT:
case SSL_DHE_DSS:
case SSL_DHE_DSS_EXPORT:
case SSL_DHE_RSA:
case SSL_DHE_RSA_EXPORT:
case SSL_Fortezza:
SSLChangeHdskState(ctx, HandshakeCertificate);
break;
default:
ASSERTMSG("Unknown key exchange method");
break;
}
break;
case SSL_certificate:
if (ctx->state == HandshakeCertificate)
switch (ctx->selectedCipherSpec->keyExchangeMethod)
{ case SSL_RSA:
case SSL_RSA_EXPORT:
case SSL_DH_DSS:
case SSL_DH_DSS_EXPORT:
case SSL_DH_RSA:
case SSL_DH_RSA_EXPORT:
SSLChangeHdskState(ctx, HandshakeHelloDone);
break;
case SSL_DHE_DSS:
case SSL_DHE_DSS_EXPORT:
case SSL_DHE_RSA:
case SSL_DHE_RSA_EXPORT:
case SSL_Fortezza:
SSLChangeHdskState(ctx, HandshakeKeyExchange);
break;
default:
ASSERTMSG("Unknown or unexpected key exchange method");
break;
}
else if (ctx->state == HandshakeClientCertificate)
{ SSLChangeHdskState(ctx, HandshakeClientKeyExchange);
if (ctx->peerCert != 0)
ctx->certReceived = 1;
}
break;
case SSL_certificate_request:
if (ctx->peerCert == 0)
{ ERR(SSLFatalSessionAlert(alert_handshake_failure, ctx));
return ERR(SSLProtocolErr);
}
ctx->certRequested = 1;
break;
case SSL_server_key_exchange:
SSLChangeHdskState(ctx, HandshakeHelloDone);
break;
case SSL_server_hello_done:
if (ctx->certRequested)
{ if (ctx->localCert != 0 && ctx->x509Requested)
{ if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeCertificate, ctx)) != 0)
return err;
}
else
{ if (ERR(err = SSLSendAlert(alert_warning, alert_no_certificate, ctx)) != 0)
return err;
}
}
if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeKeyExchange, ctx)) != 0)
return err;
assert(ctx->sslTslCalls != NULL);
if (ERR(err = ctx->sslTslCalls->generateMasterSecret(ctx)) != 0 ||
ERR(err = SSLInitPendingCiphers(ctx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
memset(ctx->preMasterSecret.data, 0, ctx->preMasterSecret.length);
if (ERR(err = SSLFreeBuffer(&ctx->preMasterSecret, &ctx->sysCtx)) != 0)
return err;
if (ctx->certSent)
if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeCertificateVerify, ctx)) != 0)
return err;
if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeChangeCipherSpec, ctx)) != 0)
return err;
if (ERR(err = SSLDisposeCipherSuite(&ctx->writeCipher, ctx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
ctx->writeCipher = ctx->writePending;
ctx->writeCipher.ready = 0;
memset(&ctx->writePending, 0, sizeof(CipherContext));
if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeFinishedMessage, ctx)) != 0)
return err;
ctx->writeCipher.ready = 1;
SSLChangeHdskState(ctx, HandshakeChangeCipherSpec);
break;
case SSL_certificate_verify:
SSLChangeHdskState(ctx, HandshakeChangeCipherSpec);
break;
case SSL_client_key_exchange:
assert(ctx->sslTslCalls != NULL);
if (ERR(err = ctx->sslTslCalls->generateMasterSecret(ctx)) != 0 ||
ERR(err = SSLInitPendingCiphers(ctx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
memset(ctx->preMasterSecret.data, 0, ctx->preMasterSecret.length);
if (ERR(err = SSLFreeBuffer(&ctx->preMasterSecret, &ctx->sysCtx)) != 0)
return err;
if (ctx->certReceived) {
SSLChangeHdskState(ctx, HandshakeClientCertVerify);
}
else {
SSLChangeHdskState(ctx, HandshakeChangeCipherSpec);
}
break;
case SSL_finished:
ctx->readCipher.ready = 1;
if (ctx->writePending.ready != 0)
{ if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeChangeCipherSpec, ctx)) != 0)
return err;
if (ERR(err = SSLDisposeCipherSuite(&ctx->writeCipher, ctx)) != 0)
{ SSLFatalSessionAlert(alert_close_notify, ctx);
return err;
}
ctx->writeCipher = ctx->writePending;
ctx->writeCipher.ready = 0;
memset(&ctx->writePending, 0, sizeof(CipherContext));
if (ERR(err = SSLPrepareAndQueueMessage(SSLEncodeFinishedMessage, ctx)) != 0)
return err;
ctx->writeCipher.ready = 1;
}
if (ctx->protocolSide == SSL_ServerSide) {
SSLChangeHdskState(ctx, HandshakeServerReady);
}
else {
SSLChangeHdskState(ctx, HandshakeClientReady);
}
if (ctx->peerID.data != 0)
ERR(SSLAddSessionData(ctx));
break;
default:
ASSERTMSG("Unknown State");
break;
}
return SSLNoErr;
}
SSLErr
SSLPrepareAndQueueMessage(EncodeMessageFunc msgFunc, SSLContext *ctx)
{ SSLErr err;
SSLRecord rec;
if (ERR(err = msgFunc(&rec, ctx)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
goto fail;
}
if (rec.contentType == SSL_handshake)
{ if (ERR(err = SSLHashSHA1.update(ctx->shaState, rec.contents)) != 0 ||
ERR(err = SSLHashMD5.update(ctx->md5State, rec.contents)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
goto fail;
}
SSLLogHdskMsg((SSLHandshakeType)rec.contents.data[0], 1);
}
assert(ctx->sslTslCalls != NULL);
if (ERR(err = ctx->sslTslCalls->writeRecord(rec, ctx)) != 0)
goto fail;
err = SSLNoErr;
fail:
SSLFreeBuffer(&rec.contents, &ctx->sysCtx);
return err;
}
SSLErr
SSL3ReceiveSSL2ClientHello(SSLRecord rec, SSLContext *ctx)
{ SSLErr err;
if (ERR(err = SSLInitMessageHashes(ctx)) != 0)
return err;
if (ERR(err = SSLHashSHA1.update(ctx->shaState, rec.contents)) != 0 ||
ERR(err = SSLHashMD5.update(ctx->md5State, rec.contents)) != 0)
{ ERR(SSLFatalSessionAlert(alert_close_notify, ctx));
return err;
}
if (ERR(err = SSLAdvanceHandshake(SSL_client_hello, ctx)) != 0)
return err;
return SSLNoErr;
}
#if LOG_HDSK_STATE
#include <stdio.h>
char *hdskStateToStr(SSLHandshakeState state)
{
static char badStr[100];
switch(state) {
case SSLUninitialized:
return "SSLUninitialized";
case HandshakeServerUninit:
return "HandshakeServerUninit";
case HandshakeClientUninit:
return "HandshakeClientUninit";
case SSLGracefulClose:
return "SSLGracefulClose";
case SSLErrorClose:
return "SSLErrorClose";
case SSLNoNotifyClose:
return "SSLNoNotifyClose";
case HandshakeServerHello:
return "HandshakeServerHello";
case HandshakeServerHelloUnknownVersion:
return "HandshakeServerHelloUnknownVersion";
case HandshakeKeyExchange:
return "HandshakeKeyExchange";
case HandshakeCertificate:
return "HandshakeCertificate";
case HandshakeHelloDone:
return "HandshakeHelloDone";
case HandshakeClientCertificate:
return "HandshakeClientCertificate";
case HandshakeClientKeyExchange:
return "HandshakeClientKeyExchange";
case HandshakeClientCertVerify:
return "HandshakeClientCertVerify";
case HandshakeChangeCipherSpec:
return "HandshakeChangeCipherSpec";
case HandshakeFinished:
return "HandshakeFinished";
case HandshakeSSL2ClientMasterKey:
return "HandshakeSSL2ClientMasterKey";
case HandshakeSSL2ClientFinished:
return "HandshakeSSL2ClientFinished";
case HandshakeSSL2ServerHello:
return "HandshakeSSL2ServerHello";
case HandshakeSSL2ServerVerify:
return "HandshakeSSL2ServerVerify";
case HandshakeSSL2ServerFinished:
return "HandshakeSSL2ServerFinished";
case HandshakeServerReady:
return "HandshakeServerReady";
case HandshakeClientReady:
return "HandshakeClientReady";
default:
sprintf(badStr, "Unknown state (%d(d)", state);
return badStr;
}
}
void SSLChangeHdskState(SSLContext *ctx, SSLHandshakeState newState)
{
printf("...hdskState = %s\n", hdskStateToStr(newState));
ctx->state = newState;
}
#endif
#if LOG_HDSK_MSG
#include <stdio.h>
static char *hdskMsgToStr(SSLHandshakeType msg)
{
static char badStr[100];
switch(msg) {
case SSL_hello_request:
return "SSL_hello_request";
case SSL_client_hello:
return "SSL_client_hello";
case SSL_server_hello:
return "SSL_server_hello";
case SSL_certificate:
return "SSL_certificate";
case SSL_server_key_exchange:
return "SSL_server_key_exchange";
case SSL_certificate_request:
return "SSL_certificate_request";
case SSL_server_hello_done:
return "SSL_server_hello_done";
case SSL_certificate_verify:
return "SSL_certificate_verify";
case SSL_client_key_exchange:
return "SSL_client_key_exchange";
case SSL_finished:
return "SSL_finished";
case SSL_MAGIC_no_certificate_alert:
return "SSL_MAGIC_no_certificate_alert";
default:
sprintf(badStr, "Unknown state (%d(d)", msg);
return badStr;
}
}
void SSLLogHdskMsg(SSLHandshakeType msg, char sent)
{
printf("---%s handshake msg %s\n",
hdskMsgToStr(msg), (sent ? "sent" : "recv"));
}
#endif