|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: ssl3msg.c
//
// Contents: Main crypto functions for SSL3.
//
// Classes:
//
// Functions:
//
// History: 04-16-96 ramas Created.
//
//----------------------------------------------------------------------------
#include <spbase.h>
//------------------------------------------------------------------------------------------
SP_STATUS WINAPI Ssl3DecryptHandler( PSPContext pContext, PSPBuffer pCommInput, PSPBuffer pAppOutput) { SP_STATUS pctRet = PCT_ERR_OK;
if(pCommInput->cbData == 0) { return PCT_INT_INCOMPLETE_MSG; }
if(!(pContext->State & SP_STATE_CONNECTED) || pContext->Decrypt == NULL) { return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); }
switch(*(PBYTE)pCommInput->pvBuffer) { case SSL3_CT_HANDSHAKE: if(pContext->RipeZombie->fProtocol & SP_PROT_CLIENTS) { // This should be either a HelloRequest message, which means that
// the server is requesting a renegotiation, or a ServerHello
// message, which means that the server is responding to a
// renegotiation request that we made.
// The first thing we need to do is to figure out which it is.
// We want to go ahead and decrypt the HelloRequest message, but
// if it's a server hello message we want to punt this back to the
// application so that they can give it to the LSA process via
// a call to InitializeSecurityContext.
// BUGBUG - We should change the context state when we request
// renegotiation and then just check the state here, but that's
// hard to do so for now we'll just check the size of the packet.
if(pCommInput->cbBuffer > sizeof(SWRAP) + sizeof(SHSH) + pContext->pCipherInfo->dwBlockSize + pContext->pHashInfo->cbCheckSum) { // Must be a ServerHello message.
pCommInput->cbData = 0;
pContext->State = SSL3_STATE_CLIENT_HELLO; } else { // This should be a HelloRequest message. We should make sure, and
// then completely consume the message.
pctRet = pContext->Decrypt( pContext, pCommInput, // message
pAppOutput); // Unpacked Message
if(PCT_ERR_OK != pctRet) { return pctRet; } if(*(PBYTE)pAppOutput->pvBuffer != SSL3_HS_HELLO_REQUEST || pAppOutput->cbData != sizeof(SHSH)) { // This ain't no HelloRequest!
return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); }
pContext->State = SSL3_STATE_GEN_HELLO_REQUEST; } } else { // This is probably a ClientHello message. In any case, let the
// caller deal with it (by passing it to the LSA process).
pCommInput->cbData = 0; pContext->State = SSL3_STATE_RENEGOTIATE; }
pAppOutput->cbData = 0;
return SP_LOG_RESULT(PCT_INT_RENEGOTIATE);
case SSL3_CT_ALERT: pctRet = pContext->Decrypt( pContext, pCommInput, pAppOutput); if(PCT_ERR_OK != pctRet) { return pctRet; }
pctRet = ParseAlertMessage(pContext, (PBYTE)pAppOutput->pvBuffer, pAppOutput->cbData);
// make sure that APP doesn't see Alert messages...
pAppOutput->cbData = 0; return pctRet;
case SSL3_CT_APPLICATIONDATA: pctRet = pContext->Decrypt( pContext, pCommInput, pAppOutput);
return pctRet;
default: return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); } }
SP_STATUS WINAPI Ssl3GetHeaderSize( PSPContext pContext, PSPBuffer pCommInput, DWORD * pcbHeaderSize) { UNREFERENCED_PARAMETER(pContext); UNREFERENCED_PARAMETER(pCommInput);
if(pcbHeaderSize == NULL) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
*pcbHeaderSize = sizeof(SWRAP); return PCT_ERR_OK; }
#if VERIFYHASH
BYTE rgb3Mac[2048]; DWORD ibMac = 0; #endif
//+---------------------------------------------------------------------------
//
// Function: Ssl3ComputeMac
//
// Synopsis:
//
// Arguments: [pContext] --
// [fReadMac] --
// [pClean] --
// [cContentType] --
// [pbMac] --
// [cbMac]
//
// History: 10-03-97 jbanes Created.
//
// Notes:
//
//----------------------------------------------------------------------------
SP_STATUS Ssl3ComputeMac( PSPContext pContext, BOOL fReadMac, PSPBuffer pClean, CHAR cContentType, PBYTE pbMac, DWORD cbMac) { HCRYPTHASH hHash = 0; DWORD dwReverseSequence; WORD wReverseData; UCHAR rgbDigest[SP_MAX_DIGEST_LEN]; DWORD cbDigest; BYTE rgbPad[CB_SSL3_MAX_MAC_PAD]; WORD cbPad; HCRYPTPROV hProv; HCRYPTKEY hSecret; DWORD dwSequence; PHashInfo pHashInfo; SP_STATUS pctRet;
UNREFERENCED_PARAMETER(cbMac);
if(fReadMac) { hProv = pContext->hReadProv; hSecret = pContext->hReadMAC; dwSequence = pContext->ReadCounter; pHashInfo = pContext->pReadHashInfo; } else { hProv = pContext->hWriteProv; hSecret = pContext->hWriteMAC; dwSequence = pContext->WriteCounter; pHashInfo = pContext->pWriteHashInfo; }
if(!hProv) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
// Determine size of pad_1 and pad_2.
if(pHashInfo->aiHash == CALG_MD5) { cbPad = CB_SSL3_MD5_MAC_PAD; } else { cbPad = CB_SSL3_SHA_MAC_PAD; }
//
// hash(MAC_write_secret + pad_2 +
// hash(MAC_write_secret + pad_1 + seq_num +
// SSLCompressed.type + SSLCompressed.length +
// SSLCompressed.fragment));
//
// Create hash
if(!CryptCreateHash(hProv, pHashInfo->aiHash, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
// Hash secret
if(!CryptHashSessionKey(hHash, hSecret, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
// hash pad 1
FillMemory(rgbPad, cbPad, PAD1_CONSTANT); if(!CryptHashData(hHash, rgbPad, cbPad, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
/* add count */ dwReverseSequence = 0; if(!CryptHashData(hHash, (PUCHAR)&dwReverseSequence, sizeof(DWORD), 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } dwReverseSequence = htonl(dwSequence); if(!CryptHashData(hHash, (PUCHAR)&dwReverseSequence, sizeof(DWORD), 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
// Add content type.
if(cContentType != 0) { if(!CryptHashData(hHash, (PBYTE)&cContentType, 1, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } }
/* add length */ wReverseData = (WORD)pClean->cbData >> 8 | (WORD)pClean->cbData << 8; if(!CryptHashData(hHash, (PBYTE)&wReverseData, sizeof(WORD), 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
/* add data */ if(!CryptHashData(hHash, pClean->pvBuffer, pClean->cbData, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
#if VERIFYHASH
if(ibMac > 1800) ibMac = 0; CopyMemory(&rgb3Mac[ibMac], (BYTE *)&dw32High, sizeof(DWORD)); ibMac += sizeof(DWORD); CopyMemory(&rgb3Mac[ibMac], (BYTE *)&dwReverseSeq, sizeof(DWORD)); ibMac += sizeof(DWORD); CopyMemory(&rgb3Mac[ibMac], (BYTE *)&wDataReverse, sizeof(WORD)); ibMac += sizeof(WORD); if(wData < 50) { CopyMemory(&rgb3Mac[ibMac], (PUCHAR)pClean->pvBuffer, wData); ibMac += wData; } #endif
// Get inner hash value.
cbDigest = sizeof(rgbDigest); if(!CryptGetHashParam(hHash, HP_HASHVAL, rgbDigest, &cbDigest, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } SP_ASSERT(pHashInfo->cbCheckSum == cbDigest);
CryptDestroyHash(hHash); hHash = 0;
#if VERIFYHASH
CopyMemory(&rgb3Mac[ibMac], rgbDigest, pHashInfo->cbCheckSum); ibMac += pHashInfo->cbCheckSum; #endif
// Create hash
if(!CryptCreateHash(hProv, pHashInfo->aiHash, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
// Hash secret
if(!CryptHashSessionKey(hHash, hSecret, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
// hash pad 2
FillMemory(rgbPad, cbPad, PAD2_CONSTANT); if(!CryptHashData(hHash, rgbPad, cbPad, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
if(!CryptHashData(hHash, rgbDigest, cbDigest, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
// Get outer hash value.
cbDigest = sizeof(rgbDigest); if(!CryptGetHashParam(hHash, HP_HASHVAL, rgbDigest, &cbDigest, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } SP_ASSERT(pHashInfo->cbCheckSum == cbDigest);
CryptDestroyHash(hHash); hHash = 0;
#if VERIFYHASH
CopyMemory(&rgb3Mac[ibMac], rgbDigest, pHashInfo->cbCheckSum); ibMac += pHashInfo->cbCheckSum; #endif
CopyMemory(pbMac, rgbDigest, cbDigest);
pctRet = PCT_ERR_OK;
cleanup:
if(hHash) { CryptDestroyHash(hHash); }
return pctRet; }
//+---------------------------------------------------------------------------
//
// Function: Ssl3BuildFinishMessage
//
// Synopsis:
//
// Arguments: [pContext] --
// [pbMd5Digest] --
// [pbSHADigest] --
// [fClient] --
//
// History: 10-03-97 jbanes Added server-side CAPI integration.
//
// Notes:
//
//----------------------------------------------------------------------------
SP_STATUS Ssl3BuildFinishMessage( PSPContext pContext, BYTE *pbMd5Digest, BYTE *pbSHADigest, BOOL fClient) { BYTE rgbPad1[CB_SSL3_MAX_MAC_PAD]; BYTE rgbPad2[CB_SSL3_MAX_MAC_PAD]; BYTE szClnt[] = "CLNT"; BYTE szSrvr[] = "SRVR"; HCRYPTHASH hHash = 0; DWORD cbDigest; SP_STATUS pctRet;
//
// Compute the two hash values as follows:
//
// enum { client(0x434c4e54), server(0x53525652) } Sender;
// enum { client("CLNT"), server("SRVR") } Sender;
//
// struct {
// opaque md5_hash[16];
// opaque sha_hash[20];
// } Finished;
//
// md5_hash - MD5(master_secret + pad2 + MD5(handshake_messages +
// Sender + master_secret + pad1))
//
// sha_hash - SHA(master_secret + pad2 + SHA(handshake_messages +
// Sender + master_secret + pad1))
//
// pad_1 - The character 0x36 repeated 48 times for MD5 or
// 40 times for SHA.
//
// pad_2 - The character 0x5c repeated the same number of times.
//
FillMemory(rgbPad1, sizeof(rgbPad1), PAD1_CONSTANT); FillMemory(rgbPad2, sizeof(rgbPad2), PAD2_CONSTANT);
// Make local copy of the handshake_messages MD5 hash object
if(!CryptDuplicateHash(pContext->hMd5Handshake, NULL, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
// Add rest of stuff to local MD5 hash object.
if(!CryptHashData(hHash, fClient ? szClnt : szSrvr, 4, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
if(!CryptHashSessionKey(hHash, pContext->RipeZombie->hMasterKey, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, rgbPad1, CB_SSL3_MD5_MAC_PAD, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } cbDigest = CB_MD5_DIGEST_LEN; if(!CryptGetHashParam(hHash, HP_HASHVAL, pbMd5Digest, &cbDigest, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } CryptDestroyHash(hHash); hHash = 0;
// Compute "parent" MD5 hash
if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, CALG_MD5, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashSessionKey(hHash, pContext->RipeZombie->hMasterKey, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, rgbPad2, CB_SSL3_MD5_MAC_PAD, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, pbMd5Digest, CB_MD5_DIGEST_LEN, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } cbDigest = CB_MD5_DIGEST_LEN; if(!CryptGetHashParam(hHash, HP_HASHVAL, pbMd5Digest, &cbDigest, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } CryptDestroyHash(hHash); hHash = 0;
// Build SHA Hash
// Make local copy of the handshake_messages SHA hash object
if(!CryptDuplicateHash(pContext->hShaHandshake, NULL, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
// SHA(handshake_messages + Sender + master_secret + pad1)
if(!CryptHashData(hHash, fClient ? szClnt : szSrvr, 4, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashSessionKey(hHash, pContext->RipeZombie->hMasterKey, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, rgbPad1, CB_SSL3_SHA_MAC_PAD, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } cbDigest = A_SHA_DIGEST_LEN; if(!CryptGetHashParam(hHash, HP_HASHVAL, pbSHADigest, &cbDigest, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } CryptDestroyHash(hHash); hHash = 0;
// SHA(master_secret + pad2 + SHA-hash);
if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, CALG_SHA, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashSessionKey(hHash, pContext->RipeZombie->hMasterKey, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, rgbPad2, CB_SSL3_SHA_MAC_PAD, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, pbSHADigest, A_SHA_DIGEST_LEN, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } cbDigest = A_SHA_DIGEST_LEN; if(!CryptGetHashParam(hHash, HP_HASHVAL, pbSHADigest, &cbDigest, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } CryptDestroyHash(hHash); hHash = 0;
pctRet = PCT_ERR_OK;
cleanup:
if(hHash) { CryptDestroyHash(hHash); }
return pctRet; }
/*****************************************************************************/ DWORD Ssl3CiphertextLen( PSPContext pContext, DWORD cbMessage, BOOL fClientIsSender) { DWORD cbBlock;
UNREFERENCED_PARAMETER(fClientIsSender);
// Abort early if we're not encrypting.
if(pContext->pWriteCipherInfo == NULL) { // Add record header length.
cbMessage += sizeof(SWRAP);
return cbMessage; }
// Add MAC length.
cbMessage += pContext->pWriteHashInfo->cbCheckSum;
// Add padding if we're using a block cipher.
cbBlock = pContext->pWriteCipherInfo->dwBlockSize; if(cbBlock > 1) { cbMessage += cbBlock - cbMessage % cbBlock; }
// Add record header length.
cbMessage += sizeof(SWRAP);
return cbMessage; }
//+---------------------------------------------------------------------------
//
// Function: Ssl3EncryptRaw
//
// Synopsis: Perform the MAC and encryption steps on an SSL3 record.
//
// Arguments: [pContext] -- Schannel context.
// [pAppInput] -- Data to be encrypted.
// [pCommOutput] -- (output) Encrypted SSL3 record.
// [bContentType] -- SSL3 context type.
//
// History: 10-22-97 jbanes CAPI integrated.
//
// Notes: This function doesn't touch the header portion of the SSL3
// record. This is handle by the calling function.
//
//----------------------------------------------------------------------------
SP_STATUS WINAPI Ssl3EncryptRaw( PSPContext pContext, PSPBuffer pAppInput, PSPBuffer pCommOutput, BYTE bContentType) { SP_STATUS pctRet; SPBuffer Clean; SPBuffer Encrypted; DWORD cbBlock; DWORD cbPadding; PUCHAR pbMAC = NULL; BOOL fIsClient = FALSE; DWORD cbBuffExpected;
if((pContext == NULL) || (pContext->RipeZombie == NULL) || (pContext->pWriteHashInfo == NULL) || (pContext->pWriteCipherInfo == NULL) || (pAppInput == NULL) || (pCommOutput == NULL) || (pAppInput->pvBuffer == NULL) || (pCommOutput->pvBuffer == NULL)) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
if(pAppInput->cbData > pAppInput->cbBuffer) { return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); } fIsClient = ( 0 != (pContext->RipeZombie->fProtocol & SP_PROT_SSL3TLS1_CLIENTS));
cbBuffExpected = Ssl3CiphertextLen(pContext, pAppInput->cbData, fIsClient); if(cbBuffExpected == 0) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
if(pCommOutput->cbBuffer < cbBuffExpected) { return SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL); }
Clean.cbData = pAppInput->cbData; Clean.pvBuffer = (PUCHAR)pCommOutput->pvBuffer + sizeof(SWRAP); Clean.cbBuffer = pCommOutput->cbBuffer - sizeof(SWRAP);
/* Move data out of the way if necessary */ if(Clean.pvBuffer != pAppInput->pvBuffer) { DebugLog((DEB_WARN, "SSL3EncryptRaw: Unnecessary Move, performance hog\n")); MoveMemory(Clean.pvBuffer, pAppInput->pvBuffer, pAppInput->cbData); }
// Transfer the write key over from the application process.
if(pContext->hWriteKey == 0 && pContext->pWriteCipherInfo->aiCipher != CALG_NULLCIPHER) { DebugLog((DEB_TRACE, "Transfer write key from user process.\n")); pctRet = SPGetUserKeys(pContext, SCH_FLAG_WRITE_KEY); if(pctRet != PCT_ERR_OK) { return SP_LOG_RESULT(pctRet); } }
// Compute MAC and add it to end of message.
pbMAC = (PUCHAR)Clean.pvBuffer + Clean.cbData; if(pContext->RipeZombie->fProtocol & SP_PROT_SSL3) { pctRet = Ssl3ComputeMac(pContext, FALSE, &Clean, bContentType, pbMAC, pContext->pWriteHashInfo->cbCheckSum); if(pctRet != PCT_ERR_OK) { return pctRet; } } else { pctRet = Tls1ComputeMac(pContext, FALSE, &Clean, bContentType, pbMAC, pContext->pWriteHashInfo->cbCheckSum); if(pctRet != PCT_ERR_OK) { return pctRet; } } Clean.cbData += pContext->pWriteHashInfo->cbCheckSum;
pContext->WriteCounter++;
// Add block cipher padding to end of message.
cbBlock = pContext->pWriteCipherInfo->dwBlockSize; if(cbBlock > 1) { // This is a block cipher.
cbPadding = cbBlock - Clean.cbData % cbBlock;
FillMemory((PUCHAR)Clean.pvBuffer + Clean.cbData, cbPadding, (UCHAR)(cbPadding - 1)); Clean.cbData += cbPadding; }
SP_ASSERT(Clean.cbData <= Clean.cbBuffer);
Encrypted.cbData = Clean.cbData; Encrypted.pvBuffer = Clean.pvBuffer; Encrypted.cbBuffer = Clean.cbBuffer;
// Encrypt message.
if(pContext->pWriteCipherInfo->aiCipher != CALG_NULLCIPHER) { if(!CryptEncrypt(pContext->hWriteKey, 0, FALSE, 0, Encrypted.pvBuffer, &Encrypted.cbData, Encrypted.cbBuffer)) { SP_LOG_RESULT(GetLastError()); return PCT_INT_INTERNAL_ERROR; } }
pCommOutput->cbData = Encrypted.cbData + sizeof(SWRAP);
return PCT_ERR_OK; }
//+---------------------------------------------------------------------------
//
// Function: Ssl3EncryptMessage
//
// Synopsis: Encode a block of data as an SSL3 record.
//
// Arguments: [pContext] -- Schannel context.
// [pAppInput] -- Data to be encrypted.
// [pCommOutput] -- (output) Completed SSL3 record.
//
// History: 10-22-97 jbanes CAPI integrated.
//
// Notes: An SSL3 record is formatted as:
//
// BYTE header[5];
// BYTE data[pAppInput->cbData];
// BYTE mac[mac_size];
// BYTE padding[padding_size];
//
//----------------------------------------------------------------------------
SP_STATUS WINAPI Ssl3EncryptMessage( PSPContext pContext, PSPBuffer pAppInput, PSPBuffer pCommOutput) { DWORD cbMessage; SP_STATUS pctRet;
SP_BEGIN("Ssl3EncryptMessage");
if((pContext == NULL) || (pContext->RipeZombie == NULL) || (pAppInput == NULL) || (pCommOutput == NULL) || (pCommOutput->pvBuffer == NULL)) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
DebugLog((DEB_TRACE, "Input: cbData:0x%x, cbBuffer:0x%x, pvBuffer:0x%8.8x\n", pAppInput->cbData, pAppInput->cbBuffer, pAppInput->pvBuffer));
DebugLog((DEB_TRACE, "Output: cbData:0x%x, cbBuffer:0x%x, pvBuffer:0x%8.8x\n", pCommOutput->cbData, pCommOutput->cbBuffer, pCommOutput->pvBuffer));
// Compute encrypted message size.
cbMessage = Ssl3CiphertextLen(pContext, pAppInput->cbData, TRUE);
pctRet = Ssl3EncryptRaw(pContext, pAppInput, pCommOutput, SSL3_CT_APPLICATIONDATA); if(pctRet != PCT_ERR_OK) { SP_RETURN(SP_LOG_RESULT(pctRet)); }
SetWrapNoEncrypt(pCommOutput->pvBuffer, SSL3_CT_APPLICATIONDATA, cbMessage - sizeof(SWRAP)); if(pContext->RipeZombie->fProtocol & SP_PROT_TLS1) { ((PUCHAR)pCommOutput->pvBuffer)[02] = TLS1_CLIENT_VERSION_LSB; }
DebugLog((DEB_TRACE, "Output: cbData:0x%x, cbBuffer:0x%x, pvBuffer:0x%8.8x\n", pCommOutput->cbData, pCommOutput->cbBuffer, pCommOutput->pvBuffer));
SP_RETURN(PCT_ERR_OK); }
//+---------------------------------------------------------------------------
//
// Function: Ssl3DecryptMessage
//
// Synopsis: Decode an SSL3 record.
//
// Arguments: [pContext] -- Schannel context.
// [pMessage] -- Data from the remote party.
// [pAppOutput] -- (output) Decrypted data.
//
// History: 10-22-97 jbanes CAPI integrated.
//
// Notes: The number of input data bytes consumed by this function
// is returned in pMessage->cbData.
//
//----------------------------------------------------------------------------
SP_STATUS WINAPI Ssl3DecryptMessage( PSPContext pContext, PSPBuffer pMessage, PSPBuffer pAppOutput) { SP_STATUS pctRet; SPBuffer Clean; SPBuffer Encrypted; UCHAR rgbDigest[SP_MAX_DIGEST_LEN]; PUCHAR pbMAC; DWORD dwLength, cbActualData; SWRAP *pswrap = pMessage->pvBuffer; DWORD dwVersion;
DWORD cbBlock; DWORD cbPadding; BOOL fBadPadding = FALSE;
SP_BEGIN("Ssl3DecryptMessage");
if((pContext == NULL) || (pContext->pReadCipherInfo == NULL) || (pContext->RipeZombie == NULL) || (pAppOutput == NULL) || (pMessage == NULL) || (pMessage->pvBuffer == NULL)) { SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR)); }
/* First determine the length of data, the length of padding,
* and the location of data, and the location of MAC */ cbActualData = pMessage->cbData; pMessage->cbData = sizeof(SWRAP); /* minimum amount of data we need */
if(cbActualData < sizeof(SWRAP)) { SP_RETURN(PCT_INT_INCOMPLETE_MSG); }
dwVersion = COMBINEBYTES(pswrap->bMajor, pswrap->bMinor); if(dwVersion != SSL3_CLIENT_VERSION && dwVersion != TLS1_CLIENT_VERSION) { SP_RETURN(SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG)); }
dwLength = COMBINEBYTES(pswrap->bcbMSBSize, pswrap->bcbLSBSize);
Encrypted.pvBuffer = (PUCHAR)pMessage->pvBuffer + sizeof(SWRAP); Encrypted.cbBuffer = pMessage->cbBuffer - sizeof(SWRAP);
pMessage->cbData += dwLength ;
if(pMessage->cbData > cbActualData) { SP_RETURN(PCT_INT_INCOMPLETE_MSG); }
Encrypted.cbData = dwLength; /* encrypted data size */
SP_ASSERT(Encrypted.cbData != 0);
cbBlock = pContext->pReadCipherInfo->dwBlockSize;
if(cbBlock > 1) { /* check to see if we have a block size violation */ if((Encrypted.cbData % cbBlock) || (Encrypted.cbData < cbBlock)) { SP_RETURN(SP_LOG_RESULT(PCT_INT_MSG_ALTERED)); } }
// Transfer the read key over from the application process.
if(pContext->hReadKey == 0 && pContext->pReadCipherInfo->aiCipher != CALG_NULLCIPHER) { DebugLog((DEB_TRACE, "Transfer read key from user process.\n")); pctRet = SPGetUserKeys(pContext, SCH_FLAG_READ_KEY); if(pctRet != PCT_ERR_OK) { return SP_LOG_RESULT(pctRet); } }
// Decrypt message.
if(pContext->pReadCipherInfo->aiCipher != CALG_NULLCIPHER) { if(!CryptDecrypt(pContext->hReadKey, 0, FALSE, 0, Encrypted.pvBuffer, &Encrypted.cbData)) { SP_LOG_RESULT(GetLastError()); SP_RETURN(PCT_INT_INTERNAL_ERROR); } }
// Remove block cipher padding.
if(cbBlock > 1) { // This is a block cipher.
cbPadding = *((PUCHAR)Encrypted.pvBuffer + Encrypted.cbData - 1) + 1;
if(pContext->RipeZombie->fProtocol & SP_PROT_SSL3) { if(cbPadding > cbBlock || cbPadding >= Encrypted.cbData) { // Invalid pad size.
DebugLog((DEB_WARN, "FINISHED Message: Padding Invalid\n")); fBadPadding = TRUE; } } else { if(cbPadding > 256 || cbPadding >= Encrypted.cbData) { // Invalid pad size.
DebugLog((DEB_WARN, "FINISHED Message: Padding Invalid\n")); fBadPadding = TRUE; } } if(!fBadPadding) { Encrypted.cbData -= cbPadding; } }
//
// Note that if the padding is bogus we don't error out right
// away. This might give an attacker some timing information with
// which he can attack the symmetric cipher (or CBC) independently
// of the MAC. Instead, we'll perform the MAC operation and then
// error out.
//
// Build buffer over which to MAC.
if(Encrypted.cbData < pContext->pReadHashInfo->cbCheckSum) { fBadPadding = TRUE;
Clean.pvBuffer = Encrypted.pvBuffer; Clean.cbData = Encrypted.cbData; Clean.cbBuffer = Clean.cbData; } else { Clean.pvBuffer = Encrypted.pvBuffer; Clean.cbData = Encrypted.cbData - pContext->pReadHashInfo->cbCheckSum; Clean.cbBuffer = Clean.cbData; }
// Validate MAC.
if(pContext->RipeZombie->fProtocol & SP_PROT_SSL3) { pctRet = Ssl3ComputeMac(pContext, TRUE, &Clean, pswrap->bCType, rgbDigest, sizeof(rgbDigest)); if(pctRet != PCT_ERR_OK) { return pctRet; } } else { pctRet = Tls1ComputeMac(pContext, TRUE, &Clean, pswrap->bCType, rgbDigest, sizeof(rgbDigest)); if(pctRet != PCT_ERR_OK) { return pctRet; } }
if(fBadPadding) { SP_RETURN(SP_LOG_RESULT(SEC_E_MESSAGE_ALTERED)); }
pContext->ReadCounter++;
pbMAC = (PUCHAR)Clean.pvBuffer + Clean.cbData;
if(memcmp(rgbDigest, pbMAC, pContext->pReadHashInfo->cbCheckSum)) { DebugLog((DEB_WARN, "FINISHED Message: Checksum Invalid\n")); if(pContext->RipeZombie->fProtocol & SP_PROT_TLS1) { SetTls1Alert(pContext, TLS1_ALERT_FATAL, TLS1_ALERT_BAD_RECORD_MAC); } SP_RETURN(SP_LOG_RESULT(SEC_E_MESSAGE_ALTERED)); }
if(pAppOutput->pvBuffer != Clean.pvBuffer) { CopyMemory(pAppOutput->pvBuffer, Clean.pvBuffer, Clean.cbData); }
pAppOutput->cbData = Clean.cbData;
SP_RETURN(PCT_ERR_OK); }
/*****************************************************************************/ // Create an encrypted Finish message, adding it to the end of the
// specified buffer object.
//
SP_STATUS SPBuildS3FinalFinish(PSPContext pContext, PSPBuffer pBuffer, BOOL fClient) { PBYTE pbMessage = (PBYTE)pBuffer->pvBuffer + pBuffer->cbData; DWORD cbFinished; SP_STATUS pctRet; DWORD cbDataOut;
BYTE rgbMd5Digest[CB_MD5_DIGEST_LEN]; BYTE rgbSHADigest[CB_SHA_DIGEST_LEN];
// Build Finished message body.
pctRet = Ssl3BuildFinishMessage(pContext, rgbMd5Digest, rgbSHADigest, fClient); if(pctRet != PCT_ERR_OK) { return pctRet; }
CopyMemory(pbMessage + sizeof(SWRAP) + sizeof(SHSH), rgbMd5Digest, CB_MD5_DIGEST_LEN); CopyMemory(pbMessage + sizeof(SWRAP) + sizeof(SHSH) + CB_MD5_DIGEST_LEN, rgbSHADigest, CB_SHA_DIGEST_LEN);
// Build Finished handshake header.
SetHandshake(pbMessage + sizeof(SWRAP), SSL3_HS_FINISHED, NULL, CB_MD5_DIGEST_LEN + CB_SHA_DIGEST_LEN); cbFinished = sizeof(SHSH) + CB_MD5_DIGEST_LEN + CB_SHA_DIGEST_LEN;
// Update handshake hash objects.
pctRet = UpdateHandshakeHash(pContext, pbMessage + sizeof(SWRAP), cbFinished, FALSE); if(pctRet != PCT_ERR_OK) { return(pctRet); }
// Add record header and encrypt message.
pctRet = SPSetWrap(pContext, pbMessage, SSL3_CT_HANDSHAKE, cbFinished, fClient, &cbDataOut);
if(pctRet != PCT_ERR_OK) { return pctRet; }
// Update buffer length.
pBuffer->cbData += cbDataOut;
SP_ASSERT(pBuffer->cbData <= pBuffer->cbBuffer);
return PCT_ERR_OK; }
SP_STATUS SPSetWrap( PSPContext pContext, PUCHAR pbMessage, UCHAR bContentType, DWORD cbPayload, BOOL fClient, DWORD *pcbDataOut) { SWRAP *pswrap = (SWRAP *)pbMessage; DWORD cbMessage; SP_STATUS pctRet = PCT_ERR_OK;
// Compute size of encrypted message.
cbMessage = Ssl3CiphertextLen(pContext, cbPayload, fClient);
if(pContext->pWriteHashInfo) { SPBuffer Clean; SPBuffer Encrypted;
Clean.pvBuffer = pbMessage + sizeof(SWRAP); Clean.cbBuffer = cbMessage; Clean.cbData = cbPayload;
Encrypted.pvBuffer = pbMessage; Encrypted.cbBuffer = cbMessage; Encrypted.cbData = cbPayload + sizeof(SWRAP);
pctRet = Ssl3EncryptRaw(pContext, &Clean, &Encrypted, bContentType); cbMessage = Encrypted.cbData; }
ZeroMemory(pswrap, sizeof(SWRAP)); pswrap->bCType = bContentType; pswrap->bMajor = SSL3_CLIENT_VERSION_MSB; if(pContext->RipeZombie->fProtocol & SP_PROT_SSL3) { pswrap->bMinor = (UCHAR)SSL3_CLIENT_VERSION_LSB; } else { pswrap->bMinor = (UCHAR)TLS1_CLIENT_VERSION_LSB; } pswrap->bcbMSBSize = MSBOF(cbMessage - sizeof(SWRAP)); pswrap->bcbLSBSize = LSBOF(cbMessage - sizeof(SWRAP));
if(pcbDataOut != NULL) { *pcbDataOut = cbMessage; }
return(pctRet); }
void SetWrapNoEncrypt( PUCHAR pbMessage, UCHAR bContentType, DWORD cbPayload) { SWRAP *pswrap = (SWRAP *)pbMessage;
ZeroMemory(pswrap, sizeof(SWRAP)); pswrap->bCType = bContentType; pswrap->bMajor = SSL3_CLIENT_VERSION_MSB; pswrap->bMinor = SSL3_CLIENT_VERSION_LSB; pswrap->bcbMSBSize = MSBOF(cbPayload); pswrap->bcbLSBSize = LSBOF(cbPayload); }
void SetHandshake(PUCHAR pb, BYTE bHandshake, PUCHAR pbData, DWORD dwSize) { SHSH *pshsh = (SHSH *) pb;
FillMemory(pshsh, sizeof(SHSH), 0); pshsh->typHS = bHandshake; pshsh->bcbMSB = MSBOF(dwSize) ; pshsh->bcbLSB = LSBOF(dwSize) ; if(NULL != pbData) { CopyMemory( pb + sizeof(SHSH) , pbData, dwSize); } }
//+---------------------------------------------------------------------------
//
// Function: UpdateHandshakeHash
//
// Synopsis:
//
// Arguments: [pContext] --
// [pb] --
// [dwcb] --
// [fInit] --
//
// History: 10-03-97 jbanes Added server-side CAPI integration.
//
// Notes:
//
//----------------------------------------------------------------------------
SP_STATUS UpdateHandshakeHash( PSPContext pContext, PUCHAR pb, DWORD dwcb, BOOL fInit) { if(pContext->RipeZombie->hMasterProv == 0) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
if(fInit) { DebugLog((DEB_TRACE, "UpdateHandshakeHash: initializing\n"));
if(pContext->hMd5Handshake) { CryptDestroyHash(pContext->hMd5Handshake); pContext->hMd5Handshake = 0; } if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, CALG_MD5, 0, 0, &pContext->hMd5Handshake)) { SP_LOG_RESULT(GetLastError()); return PCT_INT_INTERNAL_ERROR; }
if(pContext->hShaHandshake) { CryptDestroyHash(pContext->hShaHandshake); pContext->hShaHandshake = 0; } if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, CALG_SHA, 0, 0, &pContext->hShaHandshake)) { SP_LOG_RESULT(GetLastError()); return PCT_INT_INTERNAL_ERROR; } }
if(pContext->hMd5Handshake == 0 || pContext->hShaHandshake == 0) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
if(dwcb && NULL != pb) { DebugLog((DEB_TRACE, "UpdateHandshakeHash: %d bytes\n", dwcb));
if(!CryptHashData(pContext->hMd5Handshake, pb, dwcb, 0)) { SP_LOG_RESULT(GetLastError()); return PCT_INT_INTERNAL_ERROR; } if(!CryptHashData(pContext->hShaHandshake, pb, dwcb, 0)) { SP_LOG_RESULT(GetLastError()); return PCT_INT_INTERNAL_ERROR; } }
return PCT_ERR_OK; }
//+---------------------------------------------------------------------------
//
// Function: Tls1ComputeCertVerifyHashes
//
// Synopsis: Compute the hashes contained by a TLS
// CertificateVerify message.
//
// Arguments: [pContext] -- Schannel context.
// [pbHash] --
// [cbHash] --
//
// History: 10-14-97 jbanes Created.
//
// Notes: The data generated by this routine is always 36 bytes in
// length, and consists of an MD5 hash followed by an SHA
// hash.
//
// The hash values are computed as:
//
// md5_hash = MD5(handshake_messages);
//
// sha_hash = SHA(handshake_messages);
//
//----------------------------------------------------------------------------
SP_STATUS Tls1ComputeCertVerifyHashes( PSPContext pContext, // in
PBYTE pbMD5, // out
PBYTE pbSHA) // out
{ HCRYPTHASH hHash = 0; DWORD cbData;
if((pContext == NULL) || (pContext->RipeZombie == NULL)) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
if(pbMD5 != NULL) { // md5_hash = MD5(handshake_messages);
if(!CryptDuplicateHash(pContext->hMd5Handshake, NULL, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); return PCT_INT_INTERNAL_ERROR; } cbData = CB_MD5_DIGEST_LEN; if(!CryptGetHashParam(hHash, HP_HASHVAL, pbMD5, &cbData, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } SP_ASSERT(cbData == CB_MD5_DIGEST_LEN); if(!CryptDestroyHash(hHash)) { SP_LOG_RESULT(GetLastError()); } }
if(pbSHA != NULL) { // sha_hash = SHA(handshake_messages);
if(!CryptDuplicateHash(pContext->hShaHandshake, NULL, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); return PCT_INT_INTERNAL_ERROR; } cbData = CB_SHA_DIGEST_LEN; if(!CryptGetHashParam(hHash, HP_HASHVAL, pbSHA, &cbData, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_INTERNAL_ERROR; } SP_ASSERT(cbData == CB_SHA_DIGEST_LEN); if(!CryptDestroyHash(hHash)) { SP_LOG_RESULT(GetLastError()); } }
return PCT_ERR_OK; }
//+---------------------------------------------------------------------------
//
// Function: Ssl3ComputeCertVerifyHashes
//
// Synopsis: Compute the hashes contained by an SSL3
// CertificateVerify message.
//
// Arguments: [pContext] -- Schannel context.
// [pbHash] --
// [cbHash] --
//
// History: 10-14-97 jbanes Added CAPI integration.
//
// Notes: The data generated by this routine is always 36 bytes in
// length, and consists of an MD5 hash followed by an SHA
// hash.
//
// The hash values are computed as follows:
//
// md5_hash = MD5(master_secret + pad2 +
// MD5(handshake_messages + master_secret +
// pad1));
//
// sha_hash = SHA(master_secret + pad2 +
// SHA(handshake_messages + master_secret +
// pad1));
//
//----------------------------------------------------------------------------
SP_STATUS Ssl3ComputeCertVerifyHashes( PSPContext pContext, // in
PBYTE pbMD5, // out
PBYTE pbSHA) // out
{ BYTE rgbPad1[CB_SSL3_MAX_MAC_PAD]; BYTE rgbPad2[CB_SSL3_MAX_MAC_PAD]; HCRYPTHASH hHash = 0; DWORD cbData; SP_STATUS pctRet;
FillMemory(rgbPad1, sizeof(rgbPad1), PAD1_CONSTANT); FillMemory(rgbPad2, sizeof(rgbPad2), PAD2_CONSTANT);
if(pbMD5 != NULL) { //
// CertificateVerify.signature.md5_hash = MD5(master_secret + pad2 +
// MD5(handshake_messages + master_secret + pad1));
//
// Compute inner hash.
if(!CryptDuplicateHash(pContext->hMd5Handshake, NULL, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashSessionKey(hHash, pContext->RipeZombie->hMasterKey, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, rgbPad1, CB_SSL3_MD5_MAC_PAD, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } cbData = CB_MD5_DIGEST_LEN; if(!CryptGetHashParam(hHash, HP_HASHVAL, pbMD5, &cbData, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } SP_ASSERT(cbData == CB_MD5_DIGEST_LEN); if(!CryptDestroyHash(hHash)) { SP_LOG_RESULT(GetLastError()); } hHash = 0;
// Compute outer hash.
if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, CALG_MD5, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashSessionKey(hHash, pContext->RipeZombie->hMasterKey, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, rgbPad2, CB_SSL3_MD5_MAC_PAD, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, pbMD5, CB_MD5_DIGEST_LEN, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } cbData = CB_MD5_DIGEST_LEN; if(!CryptGetHashParam(hHash, HP_HASHVAL, pbMD5, &cbData, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } SP_ASSERT(cbData == CB_MD5_DIGEST_LEN); if(!CryptDestroyHash(hHash)) { SP_LOG_RESULT(GetLastError()); } hHash = 0; }
if(pbSHA != NULL) { //
// CertificateVerify.signature.sha_hash = SHA(master_secret + pad2 +
// SHA(handshake_messages + master_secret + pad1));
//
// Compute inner hash.
if(!CryptDuplicateHash(pContext->hShaHandshake, NULL, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashSessionKey(hHash, pContext->RipeZombie->hMasterKey, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, rgbPad1, CB_SSL3_SHA_MAC_PAD, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } cbData = CB_SHA_DIGEST_LEN; if(!CryptGetHashParam(hHash, HP_HASHVAL, pbSHA, &cbData, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } SP_ASSERT(cbData == CB_SHA_DIGEST_LEN); if(!CryptDestroyHash(hHash)) { SP_LOG_RESULT(GetLastError()); } hHash = 0;
// Compute outer hash.
if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, CALG_SHA, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashSessionKey(hHash, pContext->RipeZombie->hMasterKey, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, rgbPad2, CB_SSL3_SHA_MAC_PAD, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } if(!CryptHashData(hHash, pbSHA, CB_SHA_DIGEST_LEN, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } cbData = CB_SHA_DIGEST_LEN; if(!CryptGetHashParam(hHash, HP_HASHVAL, pbSHA, &cbData, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } SP_ASSERT(cbData == CB_SHA_DIGEST_LEN); if(!CryptDestroyHash(hHash)) { SP_LOG_RESULT(GetLastError()); } hHash = 0; }
pctRet = PCT_ERR_OK;
cleanup:
if(hHash) { CryptDestroyHash(hHash); }
return pctRet; }
SP_STATUS Ssl3HandleCCS(PSPContext pContext, PUCHAR pb, DWORD cbMessage) {
SP_STATUS pctRet = PCT_ERR_OK; BOOL fSender = (0 == (pContext->RipeZombie->fProtocol & SP_PROT_SSL3TLS1_CLIENTS)) ;
SP_BEGIN("Ssl3HandleCCS");
if(cbMessage != 1 || pb[0] != 0x1) { pctRet = SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE); SP_RETURN(pctRet); }
// We always zero out the read counter on receipt
// of a change cipher spec message.
pContext->ReadCounter = 0;
// Move pending ciphers to real ciphers
pctRet = ContextInitCiphers(pContext, TRUE, FALSE);
if(pctRet != PCT_ERR_OK) { SP_RETURN(pctRet); }
if(pContext->RipeZombie->fProtocol & SP_PROT_SSL3) { pctRet = Ssl3MakeReadSessionKeys(pContext); } else { pctRet = Tls1MakeReadSessionKeys(pContext); } if(pctRet != PCT_ERR_OK) { SP_RETURN(pctRet); }
if(fSender) { pContext->wS3CipherSuiteClient = (WORD)UniAvailableCiphers[pContext->dwPendingCipherSuiteIndex].CipherKind; pContext->State = SSL3_STATE_CHANGE_CIPHER_SPEC_SERVER; } else { pContext->wS3CipherSuiteServer = (WORD)UniAvailableCiphers[pContext->dwPendingCipherSuiteIndex].CipherKind; pContext->State = SSL3_STATE_CHANGE_CIPHER_SPEC_CLIENT; } SP_RETURN(PCT_ERR_OK); }
/*****************************************************************************/ // Create a (possibly encrypted) ChangeCipherSpec and an encrypted
// Finish message, adding them to the end of the specified buffer object.
//
SP_STATUS BuildCCSAndFinishMessage( PSPContext pContext, PSPBuffer pBuffer, BOOL fClient) { SP_STATUS pctRet; PBYTE pbMessage = (PBYTE)pBuffer->pvBuffer + pBuffer->cbData; DWORD cbDataOut;
// Build ChangeCipherSpec message body.
*(pbMessage + sizeof(SWRAP)) = 0x1;
// Add record header and encrypt message.
pctRet = SPSetWrap(pContext, pbMessage, SSL3_CT_CHANGE_CIPHER_SPEC, 1, fClient, &cbDataOut);
if(pctRet != PCT_ERR_OK) return(pctRet);
// Update buffer length.
pBuffer->cbData += cbDataOut;
SP_ASSERT(pBuffer->cbData <= pBuffer->cbBuffer);
// Update cipher suites.
pContext->WriteCounter = 0;
pctRet = ContextInitCiphers(pContext, FALSE, TRUE); if(pctRet != PCT_ERR_OK) { return(pctRet); }
if(pContext->RipeZombie->fProtocol & SP_PROT_SSL3) { pctRet = Ssl3MakeWriteSessionKeys(pContext); } else { pctRet = Tls1MakeWriteSessionKeys(pContext); } if(pctRet != PCT_ERR_OK) { return(pctRet); }
if(fClient) { pContext->wS3CipherSuiteClient = (WORD)UniAvailableCiphers[pContext->dwPendingCipherSuiteIndex].CipherKind; } else { pContext->wS3CipherSuiteServer = (WORD)UniAvailableCiphers[pContext->dwPendingCipherSuiteIndex].CipherKind; }
// Build Finish message.
if(pContext->RipeZombie->fProtocol & SP_PROT_SSL3) { pctRet = SPBuildS3FinalFinish(pContext, pBuffer, fClient); } else { pctRet = SPBuildTls1FinalFinish(pContext, pBuffer, fClient); }
return pctRet; }
SP_STATUS Ssl3SelectCipher ( PSPContext pContext, WORD wCipher ) { SP_STATUS pctRet=PCT_ERR_ILLEGAL_MESSAGE; DWORD i; PCipherInfo pCipherInfo = NULL; PHashInfo pHashInfo = NULL; PKeyExchangeInfo pExchInfo = NULL;
pContext->dwPendingCipherSuiteIndex = 0;
for(i = 0; i < UniNumCiphers; i++) { // Is this an SSL3 cipher suite?
if(!(UniAvailableCiphers[i].fProt & pContext->RipeZombie->fProtocol)) { continue; }
// Is this the right cipher suite?
if(UniAvailableCiphers[i].CipherKind != wCipher) { continue; }
pCipherInfo = GetCipherInfo(UniAvailableCiphers[i].aiCipher, UniAvailableCiphers[i].dwStrength); pHashInfo = GetHashInfo(UniAvailableCiphers[i].aiHash); pExchInfo = GetKeyExchangeInfo(UniAvailableCiphers[i].KeyExch);
if(!IsCipherAllowed(pContext, pCipherInfo, pContext->RipeZombie->fProtocol, pContext->RipeZombie->dwCF)) { continue; } if(!IsHashAllowed(pContext, pHashInfo, pContext->RipeZombie->fProtocol)) { continue; } if(!IsExchAllowed(pContext, pExchInfo, pContext->RipeZombie->fProtocol)) { continue; }
if(pContext->RipeZombie->fProtocol & SP_PROT_SSL3TLS1_SERVERS) { // Determine the credentials (and CSP) to use, based on the
// key exchange algorithm.
pctRet = SPPickClientCertificate(pContext, UniAvailableCiphers[i].KeyExch);
if(pctRet != PCT_ERR_OK) { continue; } }
pContext->RipeZombie->dwCipherSuiteIndex = i; pContext->RipeZombie->aiCipher = UniAvailableCiphers[i].aiCipher; pContext->RipeZombie->dwStrength = UniAvailableCiphers[i].dwStrength; pContext->RipeZombie->aiHash = UniAvailableCiphers[i].aiHash; pContext->RipeZombie->SessExchSpec = UniAvailableCiphers[i].KeyExch;
return ContextInitCiphersFromCache(pContext); }
return(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE)); }
// Server side cipher selection
SP_STATUS Ssl3SelectCipherEx( PSPContext pContext, DWORD *pCipherSpecs, DWORD cCipherSpecs) { DWORD i, j; SP_STATUS pctRet; PCipherInfo pCipherInfo = NULL; PHashInfo pHashInfo = NULL; PKeyExchangeInfo pExchInfo = NULL; PSPCredential pCred = NULL; BOOL fFound;
pContext->dwPendingCipherSuiteIndex = 0;
// Loop through the supported SSL3 cipher suites.
for(i = 0; i < UniNumCiphers; i++) { // Is this an SSL3 cipher suite?
if(!(UniAvailableCiphers[i].fProt & pContext->RipeZombie->fProtocol)) { continue; }
pCipherInfo = GetCipherInfo(UniAvailableCiphers[i].aiCipher, UniAvailableCiphers[i].dwStrength); pHashInfo = GetHashInfo(UniAvailableCiphers[i].aiHash); pExchInfo = GetKeyExchangeInfo(UniAvailableCiphers[i].KeyExch);
// Do we currently support this hash and key exchange algorithm?
if(!IsHashAllowed(pContext, pHashInfo, pContext->RipeZombie->fProtocol)) { DebugLog((DEB_TRACE, "Cipher %d - hash not supported\n", i)); continue; } if(!IsExchAllowed(pContext, pExchInfo, pContext->RipeZombie->fProtocol)) { DebugLog((DEB_TRACE, "Cipher %d - exch not supported\n", i)); continue; }
// Do we have an appropriate certificate?
if(pContext->RipeZombie->fProtocol & SP_PROT_SSL3TLS1_SERVERS) { pctRet = SPPickServerCertificate(pContext, UniAvailableCiphers[i].KeyExch);
if(pctRet != PCT_ERR_OK) { DebugLog((DEB_TRACE, "Cipher %d - certificate %d not found\n", i, UniAvailableCiphers[i].KeyExch)); continue; } } pCred = pContext->RipeZombie->pActiveServerCred;
// Do we support this encryption algorithm/key length?
if(!IsCipherSuiteAllowed(pContext, pCipherInfo, pContext->RipeZombie->fProtocol, pCred->dwCertFlags, UniAvailableCiphers[i].dwFlags)) { DebugLog((DEB_TRACE, "Cipher %d - cipher not supported\n", i)); continue; }
// Is this cipher suite supported by the client?
for(fFound = FALSE, j = 0; j < cCipherSpecs; j++) { if(UniAvailableCiphers[i].CipherKind == pCipherSpecs[j]) { fFound = TRUE; break; } } if(!fFound) { DebugLog((DEB_TRACE, "Cipher %d - not supported by client\n", i)); continue; }
if(UniAvailableCiphers[i].KeyExch == SP_EXCH_RSA_PKCS1) { // This is an RSA cipher suite, so make sure that the
// CSP supports it.
if(!IsAlgSupportedCapi(pContext->RipeZombie->fProtocol, UniAvailableCiphers + i, pCred->pCapiAlgs, pCred->cCapiAlgs)) { DebugLog((DEB_TRACE, "Cipher %d - not supported by csp\n", i)); continue; } }
if(UniAvailableCiphers[i].KeyExch == SP_EXCH_DH_PKCS3) { // This is a DH cipher suite, so make sure that the
// CSP supports it.
if(!IsAlgSupportedCapi(pContext->RipeZombie->fProtocol, UniAvailableCiphers + i, pCred->pCapiAlgs, pCred->cCapiAlgs)) { DebugLog((DEB_TRACE, "Cipher %d - not supported by csp\n", i)); continue; } }
// Use this cipher.
pContext->RipeZombie->dwCipherSuiteIndex = i; pContext->RipeZombie->aiCipher = UniAvailableCiphers[i].aiCipher; pContext->RipeZombie->dwStrength = UniAvailableCiphers[i].dwStrength; pContext->RipeZombie->aiHash = UniAvailableCiphers[i].aiHash; pContext->RipeZombie->SessExchSpec = UniAvailableCiphers[i].KeyExch; pContext->RipeZombie->dwCF = pCred->dwCertFlags;
return ContextInitCiphersFromCache(pContext); }
LogCipherMismatchEvent();
return SP_LOG_RESULT(PCT_ERR_SPECS_MISMATCH); }
/*****************************************************************************/ VOID ComputeServerExchangeHashes( PSPContext pContext, PBYTE pbServerParams, // in
INT iServerParamsLen, // in
PBYTE pbMd5HashVal, // out
PBYTE pbShaHashVal) // out
{ MD5_CTX Md5Hash; A_SHA_CTX ShaHash;
//
// md5_hash = MD5(ClientHello.random + ServerHello.random + ServerParams);
//
// sha_hash = SHA(ClientHello.random + ServerHello.random + ServerParams);
//
MD5Init(&Md5Hash); MD5Update(&Md5Hash, pContext->rgbS3CRandom, 32); MD5Update(&Md5Hash, pContext->rgbS3SRandom, 32); MD5Update(&Md5Hash, pbServerParams, iServerParamsLen); MD5Final(&Md5Hash); CopyMemory(pbMd5HashVal, Md5Hash.digest, 16);
A_SHAInit(&ShaHash); A_SHAUpdate(&ShaHash, pContext->rgbS3CRandom, 32); A_SHAUpdate(&ShaHash, pContext->rgbS3SRandom, 32); A_SHAUpdate(&ShaHash, pbServerParams, iServerParamsLen); A_SHAFinal(&ShaHash, pbShaHashVal); }
SP_STATUS UnwrapSsl3Message( PSPContext pContext, PSPBuffer pMsgInput) { SPBuffer Encrypted; SPBuffer Clean; SP_STATUS pctRet; SWRAP *pswrap = (SWRAP *)pMsgInput->pvBuffer; PBYTE pbMsg = (PBYTE)pMsgInput->pvBuffer;
//
// Validate 5 byte header.
//
// ProtocolVersion version;
if(COMBINEBYTES(pbMsg[1], pbMsg[2]) < SSL3_CLIENT_VERSION) { pctRet = SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE); }
if(COMBINEBYTES(pswrap->bcbMSBSize, pswrap->bcbLSBSize) < pContext->pReadHashInfo->cbCheckSum) { return(PCT_ERR_ILLEGAL_MESSAGE); }
Encrypted.pvBuffer = pMsgInput->pvBuffer; Encrypted.cbBuffer = pMsgInput->cbBuffer; Encrypted.cbData = pMsgInput->cbData; Clean.pvBuffer = (PUCHAR)pMsgInput->pvBuffer + sizeof(SWRAP); pctRet = Ssl3DecryptMessage(pContext, &Encrypted, &Clean); if(pctRet == PCT_ERR_OK) { pswrap->bcbMSBSize = MSBOF(Clean.cbData); pswrap->bcbLSBSize = LSBOF(Clean.cbData); } return(pctRet); }
SP_STATUS ParseAlertMessage( PSPContext pContext, PUCHAR pbAlertMsg, DWORD cbMessage ) { SP_STATUS pctRet=PCT_ERR_OK; if(cbMessage != 2) { return SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE); }
if(pbAlertMsg[0] != SSL3_ALERT_WARNING && pbAlertMsg[0] != SSL3_ALERT_FATAL) { return SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE); }
DebugLog((DEB_WARN, "AlertMessage, Alert Level - %lx\n", (DWORD)pbAlertMsg[0])); DebugLog((DEB_WARN, "AlertMessage, Alert Description - %lx\n", (DWORD)pbAlertMsg[1]));
if(pbAlertMsg[0] == SSL3_ALERT_WARNING) { switch(pbAlertMsg[1]) { case SSL3_ALERT_NO_CERTIFICATE: DebugLog((DEB_TRACE, "no_certificate alert\n")); pContext->State = SSL3_STATE_NO_CERT_ALERT; pctRet = PCT_ERR_OK; break;
case SSL3_ALERT_CLOSE_NOTIFY: DebugLog((DEB_TRACE, "close_notify alert\n")); pctRet = SEC_I_CONTEXT_EXPIRED; break;
default: DebugLog((DEB_TRACE, "Ignoring warning alert\n")); pctRet = PCT_ERR_OK; break; } } else { switch(pbAlertMsg[1]) { case SSL3_ALERT_UNEXPECTED_MESSAGE: DebugLog((DEB_TRACE, "unexpected_message alert\n")); pctRet = SP_LOG_RESULT(SEC_E_ILLEGAL_MESSAGE); break;
case TLS1_ALERT_BAD_RECORD_MAC: DebugLog((DEB_TRACE, "bad_record_mac alert\n")); pctRet = SP_LOG_RESULT(SEC_E_MESSAGE_ALTERED); break;
case TLS1_ALERT_DECRYPTION_FAILED: DebugLog((DEB_TRACE, "decryption_failed alert\n")); pctRet = SP_LOG_RESULT(SEC_E_DECRYPT_FAILURE); break;
case TLS1_ALERT_RECORD_OVERFLOW: DebugLog((DEB_TRACE, "record_overflow alert\n")); pctRet = SP_LOG_RESULT(SEC_E_ILLEGAL_MESSAGE); break;
case SSL3_ALERT_DECOMPRESSION_FAIL: DebugLog((DEB_TRACE, "decompression_fail alert\n")); pctRet = SP_LOG_RESULT(SEC_E_MESSAGE_ALTERED); break;
case SSL3_ALERT_HANDSHAKE_FAILURE: DebugLog((DEB_TRACE, "handshake_failure alert\n")); pctRet = SP_LOG_RESULT(SEC_E_ILLEGAL_MESSAGE); break;
case TLS1_ALERT_BAD_CERTIFICATE: DebugLog((DEB_TRACE, "bad_certificate alert\n")); pctRet = SP_LOG_RESULT(SEC_E_CERT_UNKNOWN); break;
case TLS1_ALERT_UNSUPPORTED_CERT: DebugLog((DEB_TRACE, "unsupported_cert alert\n")); pctRet = SP_LOG_RESULT(SEC_E_CERT_UNKNOWN); break;
case TLS1_ALERT_CERTIFICATE_REVOKED: DebugLog((DEB_TRACE, "certificate_revoked alert\n")); pctRet = SP_LOG_RESULT(CRYPT_E_REVOKED); break;
case TLS1_ALERT_CERTIFICATE_EXPIRED: DebugLog((DEB_TRACE, "certificate_expired alert\n")); pctRet = SP_LOG_RESULT(SEC_E_CERT_EXPIRED); break;
case TLS1_ALERT_CERTIFICATE_UNKNOWN: DebugLog((DEB_TRACE, "certificate_unknown alert\n")); pctRet = SP_LOG_RESULT(SEC_E_CERT_UNKNOWN); break;
case SSL3_ALERT_ILLEGAL_PARAMETER: DebugLog((DEB_TRACE, "illegal_parameter alert\n")); pctRet = SP_LOG_RESULT(SEC_E_ILLEGAL_MESSAGE); break;
case TLS1_ALERT_UNKNOWN_CA: DebugLog((DEB_TRACE, "unknown_ca alert\n")); pctRet = SP_LOG_RESULT(SEC_E_UNTRUSTED_ROOT); break;
case TLS1_ALERT_ACCESS_DENIED: DebugLog((DEB_TRACE, "access_denied alert\n")); pctRet = SP_LOG_RESULT(SEC_E_LOGON_DENIED); break;
case TLS1_ALERT_DECODE_ERROR: DebugLog((DEB_TRACE, "decode_error alert\n")); pctRet = SP_LOG_RESULT(SEC_E_ILLEGAL_MESSAGE); break;
case TLS1_ALERT_DECRYPT_ERROR: DebugLog((DEB_TRACE, "decrypt_error alert\n")); pctRet = SP_LOG_RESULT(SEC_E_DECRYPT_FAILURE); break;
case TLS1_ALERT_EXPORT_RESTRICTION: DebugLog((DEB_TRACE, "export_restriction alert\n")); pctRet = SP_LOG_RESULT(SEC_E_ILLEGAL_MESSAGE); break;
case TLS1_ALERT_PROTOCOL_VERSION: DebugLog((DEB_TRACE, "protocol_version alert\n")); pctRet = SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION); break;
case TLS1_ALERT_INSUFFIENT_SECURITY: DebugLog((DEB_TRACE, "insuffient_security alert\n")); pctRet = SP_LOG_RESULT(SEC_E_ALGORITHM_MISMATCH); break;
case TLS1_ALERT_INTERNAL_ERROR: DebugLog((DEB_TRACE, "internal_error alert\n")); pctRet = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); break;
default: DebugLog((DEB_TRACE, "Unknown fatal alert\n")); pctRet = SP_LOG_RESULT(SEC_E_ILLEGAL_MESSAGE); break; } }
return pctRet; }
void BuildAlertMessage(PBYTE pbAlertMsg, UCHAR bAlertLevel, UCHAR bAlertDesc) { ALRT *palrt = (ALRT *) pbAlertMsg;
FillMemory(palrt, sizeof(ALRT), 0);
palrt->bCType = SSL3_CT_ALERT; palrt->bMajor = SSL3_CLIENT_VERSION_MSB; // palrt->bMinor = SSL3_CLIENT_VERSION_LSB; DONE by FillMemory
// palrt->bcbMSBSize = 0; Done by FillMemory
palrt->bcbLSBSize = 2; palrt->bAlertLevel = bAlertLevel; palrt->bAlertDesc = bAlertDesc ; }
/*****************************************************************************/ // Create an encrypted Finish message, adding it to the end of the
// specified buffer object.
//
SP_STATUS SPBuildTls1FinalFinish(PSPContext pContext, PSPBuffer pBuffer, BOOL fClient) { PBYTE pbMessage = (PBYTE)pBuffer->pvBuffer + pBuffer->cbData; DWORD cbFinished; SP_STATUS pctRet; DWORD cbDataOut;
BYTE rgbDigest[CB_TLS1_VERIFYDATA];
// Build Finished message body.
pctRet = Tls1BuildFinishMessage(pContext, rgbDigest, sizeof(rgbDigest), fClient); if(pctRet != PCT_ERR_OK) { return pctRet; }
CopyMemory(pbMessage + sizeof(SWRAP) + sizeof(SHSH), rgbDigest, CB_TLS1_VERIFYDATA);
// Build Finished handshake header.
SetHandshake(pbMessage + sizeof(SWRAP), SSL3_HS_FINISHED, NULL, CB_TLS1_VERIFYDATA); cbFinished = sizeof(SHSH) + CB_TLS1_VERIFYDATA;
// Update handshake hash objects.
pctRet = UpdateHandshakeHash(pContext, pbMessage + sizeof(SWRAP), cbFinished, FALSE); if(pctRet != PCT_ERR_OK) { return(pctRet); }
// Add record header and encrypt message.
pctRet = SPSetWrap(pContext, pbMessage, SSL3_CT_HANDSHAKE, cbFinished, fClient, &cbDataOut);
if(pctRet != PCT_ERR_OK) { return(pctRet); }
// Update buffer length .
pBuffer->cbData += cbDataOut;
SP_ASSERT(pBuffer->cbData <= pBuffer->cbBuffer);
return pctRet; }
//+---------------------------------------------------------------------------
//
// Function: Tls1BuildFinishMessage
//
// Synopsis: Compute a TLS MAC for the specified message.
//
// Arguments: [pContext] -- Schannel context.
// [pbVerifyData] -- Verify data buffer.
// [cbVerifyData] -- Length of verify data buffer.
// [fClient] -- Client-generated Finished?
//
// History: 10-13-97 jbanes Created.
//
// Notes: The Finished message is computed using the following formula:
//
// verify_data = PRF(master_secret, finished_label,
// MD5(handshake_messages) +
// SHA-1(handshake_messages)) [0..11];
//
//----------------------------------------------------------------------------
SP_STATUS Tls1BuildFinishMessage( PSPContext pContext, // in
PBYTE pbVerifyData, // out
DWORD cbVerifyData, // in
BOOL fClient) // in
{ PBYTE pbLabel; DWORD cbLabel; UCHAR rgbData[CB_MD5_DIGEST_LEN + CB_SHA_DIGEST_LEN]; DWORD cbData; HCRYPTHASH hHash = 0; CRYPT_DATA_BLOB Data; SP_STATUS pctRet;
if(cbVerifyData < CB_TLS1_VERIFYDATA) { return SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL); }
if(fClient) { pbLabel = (PBYTE)TLS1_LABEL_CLIENTFINISHED; } else { pbLabel = (PBYTE)TLS1_LABEL_SERVERFINISHED; } cbLabel = CB_TLS1_LABEL_FINISHED;
// Get the MD5 hash of the handshake messages so far.
if(!CryptDuplicateHash(pContext->hMd5Handshake, NULL, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto error; }
cbData = CB_MD5_DIGEST_LEN; if(!CryptGetHashParam(hHash, HP_HASHVAL, rgbData, &cbData, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto error; }
if(!CryptDestroyHash(hHash)) { SP_LOG_RESULT(GetLastError()); } hHash = 0;
// Get the SHA hash of the handshake messages so far.
if(!CryptDuplicateHash(pContext->hShaHandshake, NULL, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto error; }
cbData = A_SHA_DIGEST_LEN; if(!CryptGetHashParam(hHash, HP_HASHVAL, rgbData + CB_MD5_DIGEST_LEN, &cbData, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto error; }
cbData = CB_MD5_DIGEST_LEN + CB_SHA_DIGEST_LEN;
if(!CryptDestroyHash(hHash)) { SP_LOG_RESULT(GetLastError()); } hHash = 0;
// Compute the PRF
if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, CALG_TLS1PRF, pContext->RipeZombie->hMasterKey, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto error; }
Data.pbData = pbLabel; Data.cbData = cbLabel; if(!CryptSetHashParam(hHash, HP_TLS1PRF_LABEL, (PBYTE)&Data, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto error; }
Data.pbData = rgbData; Data.cbData = cbData; if(!CryptSetHashParam(hHash, HP_TLS1PRF_SEED, (PBYTE)&Data, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto error; }
if(!CryptGetHashParam(hHash, HP_HASHVAL, pbVerifyData, &cbVerifyData, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto error; }
pctRet = PCT_ERR_OK;
error:
if(hHash) { if(!CryptDestroyHash(hHash)) { SP_LOG_RESULT(GetLastError()); } }
return pctRet; }
SP_STATUS SPBuildTlsAlertMessage( PSPContext pContext, // in
PSPBuffer pCommOutput) { PBYTE pbMessage = NULL; DWORD cbMessage; BOOL fAllocated = FALSE; SP_STATUS pctRet; DWORD cbDataOut;
SP_BEGIN("SPBuildTlsAlertMessage");
cbMessage = sizeof(SWRAP) + CB_SSL3_ALERT_ONLY + SP_MAX_DIGEST_LEN + SP_MAX_BLOCKCIPHER_SIZE;
if(pContext->State != TLS1_STATE_ERROR) { SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR)); }
if(pCommOutput->pvBuffer) { // Application has allocated memory.
if(pCommOutput->cbBuffer < cbMessage) { pCommOutput->cbData = cbMessage; return SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL); } fAllocated = TRUE; } else { // Schannel is to allocate memory.
pCommOutput->cbBuffer = cbMessage; pCommOutput->pvBuffer = SPExternalAlloc(cbMessage); if(pCommOutput->pvBuffer == NULL) { SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY)); } } pCommOutput->cbData = 0;
pbMessage = (PBYTE)pCommOutput->pvBuffer;
// Build alert message.
BuildAlertMessage(pbMessage, pContext->bAlertLevel, pContext->bAlertNumber);
#if DBG
DBG_HEX_STRING(DEB_TRACE, pbMessage, sizeof(ALRT)); #endif
// Build record header and encrypt message.
pctRet = SPSetWrap(pContext, pbMessage, SSL3_CT_ALERT, CB_SSL3_ALERT_ONLY, pContext->dwProtocol & SP_PROT_SSL3TLS1_CLIENTS, &cbDataOut);
if(pctRet != PCT_ERR_OK) { if(!fAllocated) { SPExternalFree(pCommOutput->pvBuffer); pCommOutput->pvBuffer = NULL; } SP_RETURN(SP_LOG_RESULT(pctRet)); }
// Update buffer length.
pCommOutput->cbData = cbDataOut;
SP_ASSERT(pCommOutput->cbData <= pCommOutput->cbBuffer);
SP_RETURN(PCT_ERR_OK); }
void SetTls1Alert( PSPContext pContext, BYTE bAlertLevel, BYTE bAlertNumber) { pContext->State = TLS1_STATE_ERROR; pContext->bAlertLevel = bAlertLevel; pContext->bAlertNumber = bAlertNumber; }
|