|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: ssl2srv.c
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 8-08-95 RichardW Created
//
//----------------------------------------------------------------------------
#include <spbase.h>
#include <ssl2msg.h>
#include <ssl2prot.h>
SP_STATUS Ssl2SrvGenerateServerFinish(PSPContext pContext, PSPBuffer pCommOutput);
SP_STATUS Ssl2SrvGenerateServerVerify(PSPContext pContext, PSPBuffer pCommOutput);
SP_STATUS Ssl2SrvVerifyClientFinishMsg(PSPContext pContext, PSPBuffer pCommInput);
#define SSL_OFFSET_OF(t, v) ((DWORD)(ULONG_PTR)&(((t)NULL)->v))
#define SSL2_CERT_TYPE_FROM_CAPI(s) X509_ASN_ENCODING
SP_STATUS WINAPI Ssl2ServerProtocolHandler( PSPContext pContext, PSPBuffer pCommInput, PSPBuffer pCommOutput) { SP_STATUS pctRet = 0; DWORD cMessageType;
DWORD dwStateTransition; BOOL fRaw = TRUE; SPBuffer MsgInput;
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_SERVER_VERIFY: case SSL2_STATE_SERVER_RESTART: pctRet = Ssl2DecryptMessage(pContext, pCommInput, &MsgInput); cMessageType = ((PUCHAR) MsgInput.pvBuffer)[0]; fRaw = FALSE; break;
case SP_STATE_SHUTDOWN: case SP_STATE_SHUTDOWN_PENDING: cMessageType = 0; break;
case SP_STATE_CONNECTED: // The server has attempted to initiate a reconnect.
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
default: if(pCommInput->cbData < 3) { return SP_LOG_RESULT(PCT_INT_INCOMPLETE_MSG); } cMessageType = ((PUCHAR) MsgInput.pvBuffer)[2]; break;
}
if (pctRet != PCT_ERR_OK) { // to handle incomplete message errors
return(pctRet); }
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;
/* Server receives client hello */ case (SSL2_MT_CLIENT_HELLO << 16) | SP_STATE_NONE: { PSsl2_Client_Hello pSsl2Hello;
// Attempt to recognize and handle various versions of client
// hello, start by trying to unpickle the most recent version, and
// then next most recent, until one unpickles. Then run the handle
// code. We can also put unpickling and handling code in here for
// SSL messages.
pctRet = Ssl2UnpackClientHello(pCommInput, &pSsl2Hello);
if (PCT_ERR_OK == pctRet) {
if (((pContext->Flags & CONTEXT_FLAG_NOCACHE) == 0) && (pSsl2Hello->cbSessionID) && (SPCacheRetrieveBySession(pContext, pSsl2Hello->SessionID, pSsl2Hello->cbSessionID, &pContext->RipeZombie)))
{ DebugLog((DEB_TRACE, "Accept client's reconnect request.\n"));
pctRet = Ssl2SrvGenRestart(pContext, pSsl2Hello, pCommOutput); if (PCT_ERR_OK == pctRet) { pContext->State = SSL2_STATE_SERVER_VERIFY; } } else { // We're doing a full handshake, so allocate a cache entry.
if(!SPCacheRetrieveNew(TRUE, pContext->pszTarget, &pContext->RipeZombie)) { pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); } else { pContext->RipeZombie->fProtocol = pContext->dwProtocol; pContext->RipeZombie->dwCF = pContext->dwRequestedCF;
SPCacheAssignNewServerCredential(pContext->RipeZombie, pContext->pCredGroup);
pctRet = Ssl2SrvHandleClientHello(pContext, pCommInput, pSsl2Hello, pCommOutput); if (PCT_ERR_OK == pctRet) { pContext->State = SSL2_STATE_SERVER_HELLO; } } } SPExternalFree(pSsl2Hello);
} 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_CLIENT_MASTER_KEY << 16) | SSL2_STATE_SERVER_HELLO:
pctRet = Ssl2SrvHandleCMKey(pContext, pCommInput, pCommOutput); if (SP_FATAL(pctRet)) { pContext->State = PCT1_STATE_ERROR; } else { if (PCT_ERR_OK == pctRet) { pContext->State = SSL2_STATE_SERVER_VERIFY; } // We received a non-fatal error, so the state doesn't change,
// giving the app time to deal with this.
} break;
case (SSL2_MT_CLIENT_FINISHED_V2 << 16) | SSL2_STATE_SERVER_VERIFY: pctRet = Ssl2SrvHandleClientFinish( 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; }
return(pctRet); }
SP_STATUS Ssl2SrvHandleClientHello( PSPContext pContext, PSPBuffer pCommInput, PSsl2_Client_Hello pHello, PSPBuffer pCommOutput) { SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE; PSPCredential pCred; Ssl2_Server_Hello Reply; DWORD cCommonCiphers; DWORD CommonCiphers[MAX_UNI_CIPHERS]; PSessCacheItem pZombie; BOOL fFound; DWORD i,j;
UNREFERENCED_PARAMETER(pCommInput);
SP_BEGIN("Ssl2SrvHandleClientHello");
pCommOutput->cbData = 0;
/* validate the buffer configuration */
if(NULL == pContext) { SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR)); } pZombie = pContext->RipeZombie;
// See if we have a cert that supports ssl2
pctRet = SPPickServerCertificate(pContext, SP_EXCH_RSA_PKCS1); if(PCT_ERR_OK != pctRet) { SP_RETURN(pctRet | PCT_INT_DROP_CONNECTION); }
pCred = pZombie->pActiveServerCred; if (!pCred) { SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR)); }
ZeroMemory(&Reply, sizeof(Reply));
//
// Calculate common ciphers:
//
cCommonCiphers = 0;
for(i = 0; i < UniNumCiphers; i++) { PCipherInfo pCipherInfo; PHashInfo pHashInfo; PKeyExchangeInfo pExchInfo;
// Is this an SSL2 cipher suite?
if(!(UniAvailableCiphers[i].fProt & pContext->RipeZombie->fProtocol)) { continue; }
pCipherInfo = GetCipherInfo(UniAvailableCiphers[i].aiCipher, UniAvailableCiphers[i].dwStrength); if(NULL == pCipherInfo) { continue; }
if(!IsCipherSuiteAllowed(pContext, pCipherInfo, pZombie->fProtocol, pZombie->dwCF, UniAvailableCiphers[i].dwFlags)) { continue; }
pHashInfo = GetHashInfo(UniAvailableCiphers[i].aiHash); if(NULL == pHashInfo) { continue; }
if(!IsHashAllowed(pContext, pHashInfo, pZombie->fProtocol)) { continue; }
pExchInfo = GetKeyExchangeInfo(UniAvailableCiphers[i].KeyExch); if(NULL == pExchInfo) { continue; } if(!IsExchAllowed(pContext, pExchInfo, pZombie->fProtocol)) { continue; }
// Is this cipher suite supported by the client?
for(fFound = FALSE, j = 0; j < pHello->cCipherSpecs; j++) { if(UniAvailableCiphers[i].CipherKind == pHello->CipherSpecs[j]) { fFound = TRUE; break; } } if(!fFound) { continue; }
// Does the CSP support this cipher suite?
if(!IsAlgSupportedCapi(pContext->RipeZombie->fProtocol, UniAvailableCiphers + i, pCred->pCapiAlgs, pCred->cCapiAlgs)) { continue; }
// Add this cipher to list.
CommonCiphers[cCommonCiphers++] = UniAvailableCiphers[i].CipherKind; }
//
// if cCommonCipers == 0, then we have none in common. At this point, we
// should generate an error response, but that is for later. For now,
// we will generate an invalid_token return, and bail out.
//
if (cCommonCiphers == 0) { pctRet = SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH); LogCipherMismatchEvent(); goto error; }
Reply.cCipherSpecs = cCommonCiphers; Reply.pCipherSpecs = CommonCiphers; Reply.SessionIdHit = 0;
Reply.CertificateType = SSL2_CERT_TYPE_FROM_CAPI(pCred->pCert->dwCertEncodingType);
// Auto allocate the certificate. !We must free them when we're done....
Reply.pCertificate = NULL; Reply.cbCertificate = 0; pctRet = SPSerializeCertificate(SP_PROT_SSL2, FALSE, &Reply.pCertificate, &Reply.cbCertificate, pCred->pCert, 0);
if (PCT_ERR_OK != pctRet) { goto error; }
/* Generate a conneciton id to use while establishing connection */
Reply.cbConnectionID = SSL2_GEN_CONNECTION_ID_LEN; pctRet = GenerateRandomBits(Reply.ConnectionID, Reply.cbConnectionID); if(!NT_SUCCESS(pctRet)) { goto error; }
CopyMemory(pContext->pConnectionID, Reply.ConnectionID, Reply.cbConnectionID); pContext->cbConnectionID = Reply.cbConnectionID;
/* keep challenge around for later */ CopyMemory( pContext->pChallenge, pHello->Challenge, pHello->cbChallenge); pContext->cbChallenge = pHello->cbChallenge;
pctRet = Ssl2PackServerHello(&Reply, pCommOutput);
if(Reply.pCertificate) { SPExternalFree(Reply.pCertificate); }
if (PCT_ERR_OK != pctRet) { goto error; } pContext->WriteCounter = 1; /* received client hello */ pContext->ReadCounter = 1; /* Sending server hello */
SP_RETURN(PCT_ERR_OK);
error:
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 Ssl2SrvGenRestart( PSPContext pContext, PSsl2_Client_Hello pHello, PSPBuffer pCommOutput) { SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE; SPBuffer SecondOutput; Ssl2_Server_Hello Reply; DWORD cbMessage, cbMsg, cPadding; PSessCacheItem pZombie;
SP_BEGIN("Ssl2SrvGenRestart");
pCommOutput->cbData = 0;
/* validate the buffer configuration */
/* make sure we have the needed authentication data area */ if (NULL == pContext) { SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR)); } pZombie = pContext->RipeZombie;
FillMemory( &Reply, sizeof( Reply ), 0 );
Reply.SessionIdHit = (DWORD)1; Reply.cCipherSpecs = 0; Reply.pCipherSpecs = NULL; Reply.pCertificate = NULL; Reply.cbCertificate = 0; Reply.CertificateType = 0;
/* Note, we generate both a server hello, and a server verify in
* this handling routing. This is because netscape will not send * us a client finish until the server verify is received */
// Load pending ciphers from cache
pctRet = ContextInitCiphersFromCache(pContext);
if(PCT_ERR_OK != pctRet) { goto error; }
pctRet = ContextInitCiphers(pContext, TRUE, TRUE);
if(PCT_ERR_OK != pctRet) { goto error; }
Reply.cbConnectionID = SSL2_GEN_CONNECTION_ID_LEN; pctRet = GenerateRandomBits(Reply.ConnectionID, Reply.cbConnectionID); if(!NT_SUCCESS(pctRet)) { goto error; }
CopyMemory(pContext->pConnectionID, Reply.ConnectionID, Reply.cbConnectionID); pContext->cbConnectionID = Reply.cbConnectionID;
/* keep challenge around for later */ CopyMemory( pContext->pChallenge, pHello->Challenge, pHello->cbChallenge); pContext->cbChallenge = pHello->cbChallenge;
// Make a new set of session keys.
pctRet = MakeSessionKeys(pContext, pContext->RipeZombie->hMasterProv, pContext->RipeZombie->hMasterKey); if(pctRet != PCT_ERR_OK) { goto error; }
// Activate session keys.
pContext->hReadKey = pContext->hPendingReadKey; pContext->hWriteKey = pContext->hPendingWriteKey; pContext->hPendingReadKey = 0; pContext->hPendingWriteKey = 0;
/* calc size of the server hello (restart only) */ cbMessage = Reply.cbConnectionID + Reply.cbCertificate + Reply.cCipherSpecs * sizeof(Ssl2_Cipher_Tuple) + SSL_OFFSET_OF(PSSL2_SERVER_HELLO, VariantData) - sizeof(SSL2_MESSAGE_HEADER);
pCommOutput->cbData = cbMessage + 2;
/* calc size of server verify */ cbMsg = sizeof(UCHAR) + pContext->cbChallenge;
cPadding = ((cbMsg+pContext->pHashInfo->cbCheckSum) % pContext->pCipherInfo->dwBlockSize); if(cPadding) { cPadding = pContext->pCipherInfo->dwBlockSize - cPadding; }
pCommOutput->cbData += cbMsg + pContext->pHashInfo->cbCheckSum + cPadding + (cPadding?3:2);
/* 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)); pCommOutput->cbBuffer = pCommOutput->cbData; }
if(pCommOutput->cbData > pCommOutput->cbBuffer) { // Required buffer size returned in pCommOutput->cbData.
SP_RETURN(PCT_INT_BUFF_TOO_SMALL); }
pctRet = Ssl2PackServerHello(&Reply, pCommOutput); if (PCT_ERR_OK != pctRet) { goto error; } pContext->WriteCounter = 1; /* received client hello */ pContext->ReadCounter = 1; /* Sending server hello */
/* Now pack the server verify message and encrypt it */ SecondOutput.pvBuffer = (PUCHAR)pCommOutput->pvBuffer+pCommOutput->cbData; SecondOutput.cbBuffer = pCommOutput->cbBuffer-pCommOutput->cbData;
pctRet = Ssl2SrvGenerateServerVerify(pContext, &SecondOutput); if (PCT_ERR_OK != pctRet) { goto error; } pCommOutput->cbData += SecondOutput.cbData;
SP_RETURN(PCT_ERR_OK);
error: SP_RETURN(pctRet | PCT_INT_DROP_CONNECTION); }
SP_STATUS Ssl2SrvHandleCMKey( PSPContext pContext, PSPBuffer pCommInput, PSPBuffer pCommOutput) { SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE; PSsl2_Client_Master_Key pMasterKey = NULL; DWORD i;
DWORD cbData; PSessCacheItem pZombie;
SP_BEGIN("Ssl2SrvHandleCMKey");
pCommOutput->cbData = 0;
pZombie = pContext->RipeZombie;
/* make sure we have the needed authentication data area */
cbData = pCommInput->cbData; pctRet = Ssl2UnpackClientMasterKey(pCommInput, &pMasterKey);
if (PCT_ERR_OK != pctRet) { // If it's an incomplete message or something, just return;
if(!SP_FATAL(pctRet)) { SP_RETURN(pctRet); } goto error; }
pctRet = PCT_ERR_ILLEGAL_MESSAGE;
/* CMK sent cleartext, so we must auto-inc the read counter */ pContext->ReadCounter++;
pContext->pCipherInfo = NULL; pContext->pHashInfo = NULL; pContext->pKeyExchInfo = NULL;
// Pick a cipher suite
pctRet = PCT_ERR_SPECS_MISMATCH; for(i = 0; i < UniNumCiphers; i++) { // Is this an SSL2 cipher suite?
if(!(UniAvailableCiphers[i].fProt & pContext->RipeZombie->fProtocol)) { continue; }
if(UniAvailableCiphers[i].CipherKind != pMasterKey->CipherKind) { continue; }
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; } break; }
pctRet = ContextInitCiphers(pContext, TRUE, TRUE); if(pctRet != PCT_ERR_OK) { SP_LOG_RESULT(pctRet); goto error; }
/* Copy over the key args */ CopyMemory( pZombie->pKeyArgs, pMasterKey->KeyArg, pMasterKey->KeyArgLen ); pZombie->cbKeyArgs = pMasterKey->KeyArgLen;
// Store the clear key in the context structure.
CopyMemory( pZombie->pClearKey, pMasterKey->ClearKey, pMasterKey->ClearKeyLen); pZombie->cbClearKey = pMasterKey->ClearKeyLen;
/* Decrypt the encrypted portion of the master key */ pctRet = pContext->pKeyExchInfo->System->GenerateServerMasterKey( pContext, pMasterKey->ClearKey, pMasterKey->ClearKeyLen, pMasterKey->pbEncryptedKey, pMasterKey->EncryptedKeyLen); if(PCT_ERR_OK != pctRet) { goto error; }
SPExternalFree( pMasterKey ); pMasterKey = NULL;
// Update keys.
pContext->hReadKey = pContext->hPendingReadKey; pContext->hWriteKey = pContext->hPendingWriteKey; pContext->hPendingReadKey = 0; pContext->hPendingWriteKey = 0;
pctRet = Ssl2SrvGenerateServerVerify(pContext, pCommOutput); SP_RETURN(pctRet);
error: if (pMasterKey) { SPExternalFree( pMasterKey ); } 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
/* 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)); } pCommOutput->cbBuffer = pCommOutput->cbData; } if(pCommOutput->cbData <= pCommOutput->cbBuffer) { ((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); } else { pCommOutput->cbData = 0; }
} SP_RETURN((PCT_INT_DROP_CONNECTION | pctRet)); }
SP_STATUS Ssl2SrvVerifyClientFinishMsg( PSPContext pContext, PSPBuffer pCommInput) { PSSL2_CLIENT_FINISHED pFinished;
SP_BEGIN("Ssl2SrvVerifyClientFinishMsg");
/* Note, there is no header in this message, as it has been pre-decrypted */ if (pCommInput->cbData != sizeof(UCHAR) + pContext->cbConnectionID) { SP_RETURN(SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG)); } pFinished = pCommInput->pvBuffer; if (pFinished->MessageId != SSL2_MT_CLIENT_FINISHED_V2) { SP_RETURN(SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG)); }
if ( memcmp(pFinished->ConnectionID, pContext->pConnectionID, pContext->cbConnectionID)) { SP_RETURN(SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG)); } SP_RETURN(PCT_ERR_OK);
}
SP_STATUS Ssl2SrvGenerateServerVerify( PSPContext pContext, PSPBuffer pCommOutput) { SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE; PSSL2_SERVER_VERIFY pVerify; DWORD HeaderSize; SPBuffer MsgOutput; DWORD cPadding; BOOL fAlloced = FALSE;
pCommOutput->cbData = 0;
SP_BEGIN("Ssl2SrvGenerateServerVerify");
MsgOutput.cbData = sizeof(UCHAR) + pContext->cbChallenge; 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; }
MsgOutput.pvBuffer= (PUCHAR)pCommOutput->pvBuffer + HeaderSize+pContext->pHashInfo->cbCheckSum;
MsgOutput.cbBuffer= pCommOutput->cbBuffer - HeaderSize-pContext->pHashInfo->cbCheckSum;
pVerify = (PSSL2_SERVER_VERIFY) MsgOutput.pvBuffer; pVerify->MessageId = SSL2_MT_SERVER_VERIFY;
CopyMemory( pVerify->ChallengeData, pContext->pChallenge, pContext->cbChallenge );
pctRet = Ssl2EncryptMessage( pContext, &MsgOutput, pCommOutput); if(PCT_ERR_OK != pctRet) { goto error; } SP_RETURN(PCT_ERR_OK);
error:
if(fAlloced && (NULL != pCommOutput->pvBuffer)) { SPExternalFree(pCommOutput->pvBuffer); pCommOutput->cbBuffer = 0; pCommOutput->cbData = 0; pCommOutput->pvBuffer = NULL;
} SP_RETURN(PCT_INT_DROP_CONNECTION | pctRet); }
SP_STATUS Ssl2SrvGenerateServerFinish( PSPContext pContext, PSPBuffer pCommOutput) { SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE; PSSL2_SERVER_FINISHED pFinish; DWORD HeaderSize; SPBuffer MsgOutput; DWORD cPadding; BOOL fAlloced = FALSE; pCommOutput->cbData = 0; SP_BEGIN("Ssl2SrvGenerateServerFinish");
/* Generate a session id to use during the session */ pContext->RipeZombie->cbSessionID = SSL2_SESSION_ID_LEN;
/* store this context in the cache */ /* note - we don't check error 'cause it's recoverable
* if we don't cache */
SPCacheAdd(pContext);
MsgOutput.cbData = sizeof(UCHAR) + pContext->RipeZombie->cbSessionID; 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-HeaderSize-pContext->pHashInfo->cbCheckSum;
pFinish = (PSSL2_SERVER_FINISHED) MsgOutput.pvBuffer; pFinish->MessageId = SSL2_MT_SERVER_FINISHED_V2;
CopyMemory( pFinish->SessionID, pContext->RipeZombie->SessionID, pContext->RipeZombie->cbSessionID );
/* Cache Context Here */
pctRet = Ssl2EncryptMessage( pContext, &MsgOutput, pCommOutput); if(PCT_ERR_OK != pctRet) { goto error; }
SP_RETURN(PCT_ERR_OK);
error:
if(fAlloced && (NULL != pCommOutput->pvBuffer)) { SPExternalFree(pCommOutput->pvBuffer); pCommOutput->cbBuffer = 0; pCommOutput->cbData = 0; pCommOutput->pvBuffer = NULL;
} SP_RETURN(PCT_INT_DROP_CONNECTION | pctRet);
}
SP_STATUS Ssl2SrvHandleClientFinish( PSPContext pContext, PSPBuffer pCommInput, PSPBuffer pCommOutput) { SP_STATUS pctRet = PCT_ERR_ILLEGAL_MESSAGE;
SP_BEGIN("Ssl2SrvHandleClientFinish");
pCommOutput->cbData = 0;
pctRet = Ssl2SrvVerifyClientFinishMsg(pContext, pCommInput); if (PCT_ERR_OK != pctRet) { SP_RETURN(pctRet); } pctRet = Ssl2SrvGenerateServerFinish(pContext, pCommOutput);
SP_RETURN(pctRet); }
|