808 lines
23 KiB
C
808 lines
23 KiB
C
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 1995.
|
||
|
//
|
||
|
// File: ssl2cli.c
|
||
|
//
|
||
|
// Contents:
|
||
|
//
|
||
|
// Classes:
|
||
|
//
|
||
|
// Functions:
|
||
|
//
|
||
|
// History: 8-08-95 RichardW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include <spbase.h>
|
||
|
#include <ssl2msg.h>
|
||
|
#include <ssl3msg.h>
|
||
|
#include <ssl2prot.h>
|
||
|
|
||
|
|
||
|
|
||
|
SP_STATUS WINAPI
|
||
|
Ssl2ClientProtocolHandler(
|
||
|
PSPContext pContext,
|
||
|
PSPBuffer pCommInput,
|
||
|
PSPBuffer pCommOutput)
|
||
|
{
|
||
|
SP_STATUS pctRet = 0;
|
||
|
DWORD cMessageType;
|
||
|
|
||
|
DWORD dwStateTransition;
|
||
|
BOOL fRaw = TRUE;
|
||
|
SPBuffer MsgInput;
|
||
|
DWORD cbMsg;
|
||
|
PUCHAR pb;
|
||
|
UCHAR bCT;
|
||
|
|
||
|
if (NULL != pCommOutput)
|
||
|
{
|
||
|
pCommOutput->cbData = 0;
|
||
|
}
|
||
|
|
||
|
MsgInput.pvBuffer = pCommInput->pvBuffer;
|
||
|
MsgInput.cbBuffer = pCommInput->cbBuffer;
|
||
|
MsgInput.cbData = pCommInput->cbData;
|
||
|
|
||
|
// In the following states, we should decrypt the message:
|
||
|
switch(pContext->State)
|
||
|
{
|
||
|
case SSL2_STATE_CLIENT_MASTER_KEY:
|
||
|
case SSL2_STATE_CLIENT_FINISH:
|
||
|
case SSL2_STATE_CLIENT_RESTART:
|
||
|
{
|
||
|
DWORD cbHeader;
|
||
|
DWORD cbPadding;
|
||
|
|
||
|
if (MsgInput.cbData < 3)
|
||
|
{
|
||
|
return PCT_INT_INCOMPLETE_MSG;
|
||
|
}
|
||
|
|
||
|
if(((PCHAR)pCommInput->pvBuffer)[0] & 0x80)
|
||
|
{
|
||
|
cbHeader = 2 + pContext->pHashInfo->cbCheckSum;
|
||
|
cbPadding = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cbHeader = 3 + pContext->pHashInfo->cbCheckSum;
|
||
|
|
||
|
cbPadding = ((PCHAR)pCommInput->pvBuffer)[2];
|
||
|
}
|
||
|
|
||
|
(PUCHAR)MsgInput.pvBuffer += cbHeader;
|
||
|
MsgInput.cbBuffer -= cbHeader;
|
||
|
MsgInput.cbData -= (cbHeader+cbPadding);
|
||
|
|
||
|
pctRet = Ssl2DecryptMessage(pContext, pCommInput, &MsgInput);
|
||
|
|
||
|
if (pctRet != PCT_ERR_OK)
|
||
|
{
|
||
|
// to handle incomplete message errors
|
||
|
return(pctRet);
|
||
|
}
|
||
|
|
||
|
cMessageType = ((PUCHAR) MsgInput.pvBuffer)[0];
|
||
|
fRaw = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case SP_STATE_SHUTDOWN:
|
||
|
case SP_STATE_SHUTDOWN_PENDING:
|
||
|
cMessageType = 0;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
if(pCommInput->cbData < 3)
|
||
|
{
|
||
|
return PCT_INT_INCOMPLETE_MSG;
|
||
|
}
|
||
|
cMessageType = ((PUCHAR) MsgInput.pvBuffer)[2];
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
dwStateTransition = pContext->State | (cMessageType<<16);
|
||
|
|
||
|
|
||
|
switch(dwStateTransition)
|
||
|
{
|
||
|
case SP_STATE_SHUTDOWN_PENDING:
|
||
|
// There's no CloseNotify in SSL2, so just transition to
|
||
|
// the shutdown state and leave the output buffer empty.
|
||
|
pContext->State = SP_STATE_SHUTDOWN;
|
||
|
break;
|
||
|
|
||
|
case SP_STATE_SHUTDOWN:
|
||
|
return PCT_INT_EXPIRED;
|
||
|
|
||
|
case (SSL2_MT_SERVER_HELLO << 16) | UNI_STATE_CLIENT_HELLO:
|
||
|
case (SSL2_MT_SERVER_HELLO << 16) | SSL2_STATE_CLIENT_HELLO:
|
||
|
{
|
||
|
PSsl2_Server_Hello pHello;
|
||
|
|
||
|
// Attempt to recognize and handle various versions of Server
|
||
|
// hello, start by trying to unpickle the oldest, and the next
|
||
|
// version, until one unpickles. Then run the handle code.
|
||
|
// We can also put unpickling and handling code in here for SSL
|
||
|
// messages.
|
||
|
|
||
|
pctRet = Ssl2UnpackServerHello(pCommInput, &pHello);
|
||
|
if (PCT_ERR_OK == pctRet)
|
||
|
{
|
||
|
if (pHello->SessionIdHit)
|
||
|
{
|
||
|
pctRet = Ssl2CliHandleServerRestart(
|
||
|
pContext,
|
||
|
pCommInput,
|
||
|
pHello,
|
||
|
pCommOutput);
|
||
|
if (PCT_ERR_OK == pctRet)
|
||
|
{
|
||
|
pContext->State = SSL2_STATE_CLIENT_RESTART;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(pContext->RipeZombie->hMasterKey != 0)
|
||
|
{
|
||
|
// We've attempted to do a reconnect and the server has
|
||
|
// blown us off. In this case we must use a new and different
|
||
|
// cache entry.
|
||
|
pContext->RipeZombie->ZombieJuju = FALSE;
|
||
|
|
||
|
if(!SPCacheClone(&pContext->RipeZombie))
|
||
|
{
|
||
|
pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pctRet == PCT_ERR_OK)
|
||
|
{
|
||
|
pctRet = Ssl2CliHandleServerHello(
|
||
|
pContext,
|
||
|
pCommInput,
|
||
|
pHello,
|
||
|
pCommOutput);
|
||
|
}
|
||
|
if (PCT_ERR_OK == pctRet)
|
||
|
{
|
||
|
pContext->State = SSL2_STATE_CLIENT_MASTER_KEY;
|
||
|
}
|
||
|
}
|
||
|
SPExternalFree(pHello);
|
||
|
}
|
||
|
else if(pctRet != PCT_INT_INCOMPLETE_MSG)
|
||
|
{
|
||
|
pctRet |= PCT_INT_DROP_CONNECTION;
|
||
|
}
|
||
|
|
||
|
if (SP_FATAL(pctRet))
|
||
|
{
|
||
|
pContext->State = PCT1_STATE_ERROR;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case (SSL2_MT_SERVER_VERIFY << 16) | SSL2_STATE_CLIENT_MASTER_KEY:
|
||
|
pctRet = Ssl2CliHandleServerVerify(
|
||
|
pContext,
|
||
|
&MsgInput,
|
||
|
pCommOutput);
|
||
|
if (PCT_ERR_OK == pctRet)
|
||
|
{
|
||
|
pContext->State =SSL2_STATE_CLIENT_FINISH;
|
||
|
}
|
||
|
if (SP_FATAL(pctRet))
|
||
|
{
|
||
|
pContext->State = PCT1_STATE_ERROR;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case (SSL2_MT_SERVER_VERIFY << 16) | SSL2_STATE_CLIENT_RESTART:
|
||
|
pctRet = Ssl2CliFinishRestart(pContext, &MsgInput, pCommOutput);
|
||
|
if (PCT_ERR_OK == pctRet)
|
||
|
{
|
||
|
pContext->State =SSL2_STATE_CLIENT_FINISH;
|
||
|
}
|
||
|
if (SP_FATAL(pctRet))
|
||
|
{
|
||
|
pContext->State = PCT1_STATE_ERROR;
|
||
|
}
|
||
|
|
||
|
// Note, we will transmit no data, but we expect a server finished message.
|
||
|
// If the SSPI EXTRA DATA message is not processed by wininet
|
||
|
// then we may be in trouble.
|
||
|
|
||
|
break;
|
||
|
|
||
|
case (SSL2_MT_SERVER_FINISHED_V2 << 16) | SSL2_STATE_CLIENT_FINISH:
|
||
|
pctRet = Ssl2CliHandleServerFinish(
|
||
|
pContext,
|
||
|
&MsgInput,
|
||
|
pCommOutput);
|
||
|
if (SP_FATAL(pctRet))
|
||
|
{
|
||
|
pContext->State = PCT1_STATE_ERROR;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (PCT_ERR_OK == pctRet)
|
||
|
{
|
||
|
pContext->State = SP_STATE_CONNECTED;
|
||
|
pContext->DecryptHandler = Ssl2DecryptHandler;
|
||
|
pContext->Encrypt = Ssl2EncryptMessage;
|
||
|
pContext->Decrypt = Ssl2DecryptMessage;
|
||
|
pContext->GetHeaderSize = Ssl2GetHeaderSize;
|
||
|
}
|
||
|
// We received a non-fatal error, so the state doesn't
|
||
|
// change, giving the app time to deal with this.
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DebugLog((DEB_WARN, "Error in protocol, dwStateTransition is %lx\n", dwStateTransition));
|
||
|
pContext->State = PCT1_STATE_ERROR;
|
||
|
pctRet = SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
|
||
|
break;
|
||
|
}
|
||
|
if (pctRet & PCT_INT_DROP_CONNECTION)
|
||
|
{
|
||
|
pContext->State &= ~SP_STATE_CONNECTED;
|
||
|
}
|
||
|
// To handle incomplete message errors:
|
||
|
return(pctRet);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
SP_STATUS
|
||
|
Ssl2CliHandleServerHello(
|
||
|
PSPContext pContext,
|
||
|
PSPBuffer pCommInput,
|
||
|
PSsl2_Server_Hello pHello,
|
||
|
PSPBuffer pCommOutput)
|
||
|
{
|
||
|
/* error to return to peer */
|
||
|
SP_STATUS pctRet=PCT_ERR_ILLEGAL_MESSAGE;
|
||
|
|
||
|
Ssl2_Client_Master_Key Key;
|
||
|
DWORD i,j;
|
||
|
PUCHAR pPortionToEncrypt;
|
||
|
PSessCacheItem pZombie;
|
||
|
|
||
|
pCommOutput->cbData = 0;
|
||
|
|
||
|
|
||
|
SP_BEGIN("Ssl2CliHandleServerHello");
|
||
|
|
||
|
|
||
|
pZombie = pContext->RipeZombie;
|
||
|
|
||
|
do {
|
||
|
|
||
|
|
||
|
pContext->ReadCounter++;
|
||
|
|
||
|
#if DBG
|
||
|
DebugLog((DEB_TRACE, "Hello = %x\n", pHello));
|
||
|
DebugLog((DEB_TRACE, " Session ID hit \t%s\n", pHello->SessionIdHit ? "Yes" : "No"));
|
||
|
DebugLog((DEB_TRACE, " Certificate Type\t%d\n", pHello->CertificateType));
|
||
|
DebugLog((DEB_TRACE, " Certificate Len\t%d\n", pHello->cbCertificate));
|
||
|
DebugLog((DEB_TRACE, " cCipherSpecs \t%d\n", pHello->cCipherSpecs));
|
||
|
DebugLog((DEB_TRACE, " ConnectionId \t%d\n", pHello->cbConnectionID));
|
||
|
for (i = 0 ; i < pHello->cCipherSpecs ; i++ )
|
||
|
{
|
||
|
DebugLog((DEB_TRACE, " Cipher[%i] = %06x (%s)\n", i, pHello->pCipherSpecs[i],
|
||
|
DbgGetNameOfCrypto(pHello->pCipherSpecs[i]) ));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* Cycle throug the array of cipher tuples to spec mappings
|
||
|
* to find one that we support */
|
||
|
|
||
|
pContext->pCipherInfo = NULL;
|
||
|
pContext->pHashInfo = NULL;
|
||
|
pContext->pKeyExchInfo = NULL;
|
||
|
|
||
|
for(j=0;j<pHello->cCipherSpecs;j++)
|
||
|
{
|
||
|
for(i = 0; i < UniNumCiphers; i++)
|
||
|
{
|
||
|
if(UniAvailableCiphers[i].CipherKind == pHello->pCipherSpecs[j])
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if(i >= UniNumCiphers)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
if(UniAvailableCiphers[i].CipherKind != pHello->pCipherSpecs[j])
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Some servers send SSL3 cipher suites in the ServerHello
|
||
|
// message. Skip over these.
|
||
|
if((UniAvailableCiphers[i].fProt & SP_PROT_SSL2_CLIENT) == 0)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Copy all of the spec's to the cache
|
||
|
pZombie->fProtocol = SP_PROT_SSL2_CLIENT;
|
||
|
pZombie->aiCipher = UniAvailableCiphers[i].aiCipher;
|
||
|
pZombie->dwStrength = UniAvailableCiphers[i].dwStrength;
|
||
|
pZombie->aiHash = UniAvailableCiphers[i].aiHash;
|
||
|
pZombie->SessExchSpec = UniAvailableCiphers[i].KeyExch;
|
||
|
|
||
|
pctRet = ContextInitCiphersFromCache(pContext);
|
||
|
|
||
|
if(pctRet != PCT_ERR_OK)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
Key.CipherKind = pHello->pCipherSpecs[j];
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Go ahead and initialize the ciphers
|
||
|
pctRet = ContextInitCiphers(pContext, TRUE, TRUE);
|
||
|
if(pctRet != PCT_ERR_OK)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
pctRet = SPLoadCertificate(pZombie->fProtocol,
|
||
|
pHello->CertificateType,
|
||
|
pHello->pCertificate,
|
||
|
pHello->cbCertificate,
|
||
|
&pZombie->pRemoteCert);
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
if(pctRet != PCT_ERR_OK)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
if(pContext->RipeZombie->pRemotePublic != NULL)
|
||
|
{
|
||
|
SPExternalFree(pContext->RipeZombie->pRemotePublic);
|
||
|
pContext->RipeZombie->pRemotePublic = NULL;
|
||
|
}
|
||
|
|
||
|
pctRet = SPPublicKeyFromCert(pZombie->pRemoteCert,
|
||
|
&pZombie->pRemotePublic,
|
||
|
NULL);
|
||
|
|
||
|
if(PCT_ERR_OK != pctRet)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Automatically validate server certificate if appropriate
|
||
|
// context flag is set.
|
||
|
pctRet = AutoVerifyServerCertificate(pContext);
|
||
|
if(pctRet != PCT_ERR_OK)
|
||
|
{
|
||
|
SP_LOG_RESULT(pctRet);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Generate Key Args
|
||
|
if(pContext->pCipherInfo->dwBlockSize > 1)
|
||
|
{
|
||
|
GenerateRandomBits(pZombie->pKeyArgs, pContext->pCipherInfo->dwBlockSize);
|
||
|
pZombie->cbKeyArgs = Key.KeyArgLen = pContext->pCipherInfo->dwBlockSize;
|
||
|
|
||
|
/* Copy over the key args */
|
||
|
CopyMemory(Key.KeyArg,
|
||
|
pZombie->pKeyArgs,
|
||
|
pZombie->cbKeyArgs );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Key.KeyArgLen = 0;
|
||
|
}
|
||
|
|
||
|
CopyMemory(pContext->pConnectionID, pHello->ConnectionID, pHello->cbConnectionID);
|
||
|
pContext->cbConnectionID = pHello->cbConnectionID;
|
||
|
|
||
|
|
||
|
pctRet = pContext->pKeyExchInfo->System->GenerateClientExchangeValue(
|
||
|
pContext,
|
||
|
NULL,
|
||
|
0,
|
||
|
Key.ClearKey,
|
||
|
&Key.ClearKeyLen,
|
||
|
NULL,
|
||
|
&Key.EncryptedKeyLen);
|
||
|
if(PCT_ERR_OK != pctRet)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Key.pbEncryptedKey = SPExternalAlloc(Key.EncryptedKeyLen);
|
||
|
if(Key.pbEncryptedKey == NULL)
|
||
|
{
|
||
|
pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pctRet = pContext->pKeyExchInfo->System->GenerateClientExchangeValue(
|
||
|
pContext,
|
||
|
NULL,
|
||
|
0,
|
||
|
Key.ClearKey,
|
||
|
&Key.ClearKeyLen,
|
||
|
Key.pbEncryptedKey,
|
||
|
&Key.EncryptedKeyLen);
|
||
|
if(PCT_ERR_OK != pctRet)
|
||
|
{
|
||
|
SPExternalFree(Key.pbEncryptedKey);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Activate session keys.
|
||
|
pContext->hReadKey = pContext->hPendingReadKey;
|
||
|
pContext->hWriteKey = pContext->hPendingWriteKey;
|
||
|
pContext->hPendingReadKey = 0;
|
||
|
pContext->hPendingWriteKey = 0;
|
||
|
|
||
|
|
||
|
pctRet = Ssl2PackClientMasterKey(&Key, pCommOutput);
|
||
|
|
||
|
SPExternalFree(Key.pbEncryptedKey);
|
||
|
|
||
|
if(PCT_ERR_OK != pctRet)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pContext->WriteCounter++;
|
||
|
SP_RETURN(PCT_ERR_OK);
|
||
|
} while(TRUE);
|
||
|
|
||
|
if((pContext->Flags & CONTEXT_FLAG_EXT_ERR) &&
|
||
|
(pctRet == PCT_ERR_SPECS_MISMATCH))
|
||
|
{
|
||
|
// Our SSL2 implementation does not do client auth,
|
||
|
// so there is only one error message, cipher error.
|
||
|
pCommOutput->cbData = 3; // MSG-ERROR + ERROR-CODE-MSB + ERROR-CODE-LSB
|
||
|
|
||
|
if(pCommOutput->pvBuffer == NULL)
|
||
|
{
|
||
|
pCommOutput->pvBuffer = SPExternalAlloc(pCommOutput->cbData);
|
||
|
if (NULL == pCommOutput->pvBuffer)
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
|
||
|
}
|
||
|
pCommOutput->cbBuffer = pCommOutput->cbData;
|
||
|
}
|
||
|
if(pCommOutput->cbData > pCommOutput->cbBuffer)
|
||
|
{
|
||
|
// Required buffer size returned in pCommOutput->cbData.
|
||
|
SP_RETURN(SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL));
|
||
|
}
|
||
|
((PUCHAR)pCommOutput->pvBuffer)[0] = SSL2_MT_ERROR;
|
||
|
((PUCHAR)pCommOutput->pvBuffer)[1] = MSBOF(SSL_PE_NO_CIPHER);
|
||
|
((PUCHAR)pCommOutput->pvBuffer)[2] = LSBOF(SSL_PE_NO_CIPHER);
|
||
|
}
|
||
|
SP_RETURN(pctRet | PCT_INT_DROP_CONNECTION);
|
||
|
|
||
|
}
|
||
|
|
||
|
SP_STATUS
|
||
|
Ssl2CliHandleServerRestart(
|
||
|
PSPContext pContext,
|
||
|
PSPBuffer pCommInput,
|
||
|
PSsl2_Server_Hello pHello,
|
||
|
PSPBuffer pCommOutput)
|
||
|
{
|
||
|
/* error to return to peer */
|
||
|
SP_STATUS pctRet=PCT_ERR_ILLEGAL_MESSAGE;
|
||
|
PSessCacheItem pZombie;
|
||
|
|
||
|
pCommOutput->cbData = 0;
|
||
|
|
||
|
|
||
|
SP_BEGIN("Ssl2CliHandleServerRestart");
|
||
|
|
||
|
pZombie = pContext->RipeZombie;
|
||
|
|
||
|
do {
|
||
|
pContext->ReadCounter++;
|
||
|
|
||
|
|
||
|
/* if there's no zombie, the message is wrong. We can't restart. */
|
||
|
|
||
|
if(pZombie == NULL)
|
||
|
{
|
||
|
pctRet = SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(!pZombie->hMasterKey)
|
||
|
{
|
||
|
pctRet = SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(!pZombie->ZombieJuju)
|
||
|
{
|
||
|
DebugLog((DEB_WARN, "Session expired on client machine, but not on server.\n"));
|
||
|
}
|
||
|
|
||
|
CopyMemory(pContext->pConnectionID,
|
||
|
pHello->ConnectionID,
|
||
|
pHello->cbConnectionID);
|
||
|
|
||
|
pContext->cbConnectionID = pHello->cbConnectionID;
|
||
|
|
||
|
|
||
|
/* Cert length, Cipher Specs, and Cert Type should be zero */
|
||
|
|
||
|
// We know what our ciphers are, so init the cipher system
|
||
|
pctRet = ContextInitCiphersFromCache(pContext);
|
||
|
|
||
|
if(PCT_ERR_OK != pctRet)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pctRet = ContextInitCiphers(pContext, TRUE, TRUE);
|
||
|
|
||
|
if(PCT_ERR_OK != pctRet)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Make a new set of session keys.
|
||
|
pctRet = MakeSessionKeys(pContext,
|
||
|
pContext->RipeZombie->hMasterProv,
|
||
|
pContext->RipeZombie->hMasterKey);
|
||
|
if(PCT_ERR_OK != pctRet)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Activate session keys.
|
||
|
pContext->hReadKey = pContext->hPendingReadKey;
|
||
|
pContext->hWriteKey = pContext->hPendingWriteKey;
|
||
|
pContext->hPendingReadKey = 0;
|
||
|
pContext->hPendingWriteKey = 0;
|
||
|
|
||
|
/* okay, now send the client finish */
|
||
|
pctRet = Ssl2GenCliFinished(pContext, pCommOutput);
|
||
|
|
||
|
SP_RETURN(pctRet);
|
||
|
} while(TRUE);
|
||
|
|
||
|
SP_RETURN(pctRet | PCT_INT_DROP_CONNECTION);
|
||
|
}
|
||
|
|
||
|
|
||
|
SP_STATUS
|
||
|
Ssl2GenCliFinished(
|
||
|
PSPContext pContext,
|
||
|
PSPBuffer pCommOutput)
|
||
|
{
|
||
|
SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE;
|
||
|
|
||
|
PSSL2_SERVER_VERIFY pVerify = NULL;
|
||
|
PSSL2_CLIENT_FINISHED pFinish;
|
||
|
DWORD HeaderSize;
|
||
|
SPBuffer MsgOutput;
|
||
|
DWORD cPadding;
|
||
|
BOOL fAlloced=FALSE;
|
||
|
|
||
|
SP_BEGIN("Ssl2GenCliFinished");
|
||
|
|
||
|
|
||
|
|
||
|
pCommOutput->cbData = 0;
|
||
|
|
||
|
MsgOutput.cbData = sizeof(UCHAR) + pContext->cbConnectionID;
|
||
|
cPadding = ((MsgOutput.cbData+pContext->pHashInfo->cbCheckSum) % pContext->pCipherInfo->dwBlockSize);
|
||
|
if(cPadding)
|
||
|
{
|
||
|
cPadding = pContext->pCipherInfo->dwBlockSize - cPadding;
|
||
|
}
|
||
|
|
||
|
HeaderSize = (cPadding?3:2);
|
||
|
|
||
|
pCommOutput->cbData = MsgOutput.cbData +
|
||
|
pContext->pHashInfo->cbCheckSum +
|
||
|
cPadding +
|
||
|
HeaderSize;
|
||
|
|
||
|
/* are we allocating our own memory? */
|
||
|
if(pCommOutput->pvBuffer == NULL)
|
||
|
{
|
||
|
pCommOutput->pvBuffer = SPExternalAlloc(pCommOutput->cbData);
|
||
|
|
||
|
if (NULL == pCommOutput->pvBuffer)
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
|
||
|
}
|
||
|
fAlloced = TRUE;
|
||
|
pCommOutput->cbBuffer = pCommOutput->cbData;
|
||
|
}
|
||
|
|
||
|
if(pCommOutput->cbData > pCommOutput->cbBuffer)
|
||
|
{
|
||
|
// Required buffer size returned in pCommOutput->cbData.
|
||
|
SP_RETURN(SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL));
|
||
|
}
|
||
|
MsgOutput.pvBuffer= (PUCHAR)pCommOutput->pvBuffer +
|
||
|
HeaderSize +
|
||
|
pContext->pHashInfo->cbCheckSum;
|
||
|
|
||
|
MsgOutput.cbBuffer = pCommOutput->cbBuffer -
|
||
|
(pContext->pHashInfo->cbCheckSum + HeaderSize);
|
||
|
|
||
|
|
||
|
pFinish = (PSSL2_CLIENT_FINISHED) MsgOutput.pvBuffer;
|
||
|
pFinish->MessageId = SSL2_MT_CLIENT_FINISHED_V2;
|
||
|
|
||
|
CopyMemory( pFinish->ConnectionID,
|
||
|
pContext->pConnectionID,
|
||
|
pContext->cbConnectionID );
|
||
|
|
||
|
pctRet = Ssl2EncryptMessage( pContext, &MsgOutput, pCommOutput);
|
||
|
if(PCT_ERR_OK != pctRet)
|
||
|
{
|
||
|
SPExternalFree(pCommOutput->pvBuffer);
|
||
|
pCommOutput->pvBuffer = NULL;
|
||
|
pctRet |= PCT_INT_DROP_CONNECTION;
|
||
|
pCommOutput->cbBuffer = 0;
|
||
|
}
|
||
|
|
||
|
SP_RETURN(pctRet);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
SP_STATUS
|
||
|
Ssl2CliHandleServerVerify(
|
||
|
PSPContext pContext,
|
||
|
PSPBuffer pCommInput,
|
||
|
PSPBuffer pCommOutput)
|
||
|
{
|
||
|
SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE;
|
||
|
|
||
|
PSSL2_SERVER_VERIFY pVerify = NULL;
|
||
|
|
||
|
/* Read and Write Counters are incremented by the encrypt and decrypt */
|
||
|
SP_BEGIN("Ssl2CliHandleServerVerify");
|
||
|
|
||
|
|
||
|
|
||
|
pCommOutput->cbData = 0;
|
||
|
|
||
|
/* Note, there is no header in this message, as it has been pre-decrypted */
|
||
|
if(pCommInput->cbData != sizeof(UCHAR) + pContext->cbChallenge)
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
|
||
|
}
|
||
|
|
||
|
pVerify = pCommInput->pvBuffer;
|
||
|
|
||
|
if (pVerify->MessageId != SSL2_MT_SERVER_VERIFY)
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
|
||
|
}
|
||
|
|
||
|
if (memcmp( pVerify->ChallengeData,
|
||
|
pContext->pChallenge,
|
||
|
pContext->cbChallenge) )
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
|
||
|
}
|
||
|
|
||
|
|
||
|
pctRet = Ssl2GenCliFinished( pContext, pCommOutput);
|
||
|
SP_RETURN(pctRet);
|
||
|
}
|
||
|
|
||
|
SP_STATUS
|
||
|
Ssl2CliFinishRestart(
|
||
|
PSPContext pContext,
|
||
|
PSPBuffer pCommInput,
|
||
|
PSPBuffer pCommOutput)
|
||
|
{
|
||
|
SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE;
|
||
|
|
||
|
PSSL2_SERVER_VERIFY pVerify = NULL;
|
||
|
|
||
|
/* Read and Write Counters are incremented by the encrypt and decrypt */
|
||
|
SP_BEGIN("Ssl2CliFinishRestart");
|
||
|
|
||
|
|
||
|
|
||
|
pCommOutput->cbData = 0;
|
||
|
|
||
|
/* Note, there is no header in this message, as it has been pre-decrypted */
|
||
|
if(pCommInput->cbData != sizeof(UCHAR) + pContext->cbChallenge)
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
|
||
|
}
|
||
|
|
||
|
pVerify = pCommInput->pvBuffer;
|
||
|
|
||
|
if (pVerify->MessageId != SSL2_MT_SERVER_VERIFY)
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
|
||
|
}
|
||
|
|
||
|
if (memcmp( pVerify->ChallengeData,
|
||
|
pContext->pChallenge,
|
||
|
pContext->cbChallenge) )
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
|
||
|
}
|
||
|
SP_RETURN(PCT_ERR_OK);
|
||
|
}
|
||
|
|
||
|
SP_STATUS
|
||
|
Ssl2CliHandleServerFinish(
|
||
|
PSPContext pContext,
|
||
|
PSPBuffer pCommInput,
|
||
|
PSPBuffer pCommOutput)
|
||
|
{
|
||
|
SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE;
|
||
|
|
||
|
PSSL2_SERVER_FINISHED pFinished = NULL;
|
||
|
|
||
|
SP_BEGIN("Ssl2CliHandleServerFinish");
|
||
|
|
||
|
|
||
|
|
||
|
pCommOutput->cbData = 0;
|
||
|
|
||
|
|
||
|
/* Note, there is no header in this message, as it has been pre-decrypted */
|
||
|
if(pCommInput->cbData < sizeof(UCHAR))
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
|
||
|
}
|
||
|
|
||
|
pFinished = pCommInput->pvBuffer;
|
||
|
|
||
|
if (pFinished->MessageId != SSL2_MT_SERVER_FINISHED_V2)
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
|
||
|
}
|
||
|
|
||
|
if((pCommInput->cbData-1) != SSL2_SESSION_ID_LEN)
|
||
|
{
|
||
|
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
|
||
|
}
|
||
|
CopyMemory( pContext->RipeZombie->SessionID,
|
||
|
pFinished->SessionID,
|
||
|
pCommInput->cbData - 1);
|
||
|
pContext->RipeZombie->cbSessionID = pCommInput->cbData - 1;
|
||
|
|
||
|
SPCacheAdd(pContext);
|
||
|
|
||
|
SP_RETURN(PCT_ERR_OK);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|