|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: ssl2msg.c
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 10-21-97 jbanes Added CAPI integration
//
//----------------------------------------------------------------------------
#include <spbase.h>
#if 0
Ssl2CipherMap Ssl2CipherRank[] = { {SSL_CK_RC4_128_WITH_MD5, CALG_MD5, CALG_RC4, 128, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX}, {SSL_CK_DES_192_EDE3_CBC_WITH_MD5, CALG_MD5, CALG_3DES, 168, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX}, {SSL_CK_RC2_128_CBC_WITH_MD5, CALG_MD5, CALG_RC2, 128, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX}, {SSL_CK_RC4_128_FINANCE64_WITH_MD5, CALG_MD5, CALG_RC4, 64, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX}, {SSL_CK_DES_64_CBC_WITH_MD5, CALG_MD5, CALG_DES, 56, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX}, {SSL_CK_RC4_128_EXPORT40_WITH_MD5, CALG_MD5, CALG_RC4, 40, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX}, {SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, CALG_MD5, CALG_RC2, 40, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX} }; DWORD Ssl2NumCipherRanks = sizeof(Ssl2CipherRank)/sizeof(Ssl2CipherMap); #endif
#if 0
CertTypeMap aSsl2CertEncodingPref[] = { { X509_ASN_ENCODING, 0} };
DWORD cSsl2CertEncodingPref = sizeof(aSsl2CertEncodingPref)/sizeof(CertTypeMap); #endif
SP_STATUS WINAPI Ssl2DecryptHandler( PSPContext pContext, PSPBuffer pCommInput, PSPBuffer pAppOutput) { SP_STATUS pctRet = PCT_ERR_OK;
if (pCommInput->cbData > 0) { // First, we'll handle incoming data packets:
if ((pContext->State & SP_STATE_CONNECTED) && pContext->Decrypt) { pctRet = pContext->Decrypt( pContext, pCommInput, // message
pAppOutput); // Unpacked Message
if (PCT_ERR_OK == pctRet) { /* look for escapes */ } return(pctRet); } else { return(SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG)); } } return (PCT_INT_INCOMPLETE_MSG); }
//+---------------------------------------------------------------------------
//
// Function: Ssl2ComputeMac
//
// Synopsis: Compute an SSL2 message MAC.
//
// Arguments: [pContext] -- Schannel context.
//
// History: 10-22-97 jbanes Created.
//
// Notes: MAC_DATA := Hash(key + data + sequence_number)
//
//----------------------------------------------------------------------------
static SP_STATUS Ssl2ComputeMac( PSPContext pContext, // in
BOOL fWriteMAC, // in
DWORD dwSequence, // in
PSPBuffer pData, // in
PBYTE pbMac, // out
DWORD cbMac) // in
{ DWORD dwReverseSequence; BYTE rgbSalt[SP_MAX_MASTER_KEY]; DWORD cbSalt; HCRYPTHASH hHash; HCRYPTKEY hKey;
// Make sure output buffer is big enough.
if(cbMac < pContext->pHashInfo->cbCheckSum) { return SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL); }
dwReverseSequence = htonl(dwSequence);
hKey = fWriteMAC ? pContext->hWriteKey : pContext->hReadKey;
if(!CryptCreateHash(pContext->RipeZombie->hMasterProv, pContext->pHashInfo->aiHash, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); SP_RETURN(PCT_INT_INTERNAL_ERROR); }
if(!CryptHashSessionKey(hHash, hKey, CRYPT_LITTLE_ENDIAN)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); SP_RETURN(PCT_INT_INTERNAL_ERROR); } cbSalt = sizeof(rgbSalt); if(!CryptGetKeyParam(hKey, KP_SALT, rgbSalt, &cbSalt, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); SP_RETURN(PCT_INT_INTERNAL_ERROR); } if(!CryptHashData(hHash, rgbSalt, cbSalt, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); SP_RETURN(PCT_INT_INTERNAL_ERROR); }
if(!CryptHashData(hHash, pData->pvBuffer, pData->cbData, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); SP_RETURN(PCT_INT_INTERNAL_ERROR); }
if(!CryptHashData(hHash, (PBYTE)&dwReverseSequence, sizeof(DWORD), 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); SP_RETURN(PCT_INT_INTERNAL_ERROR); }
if(!CryptGetHashParam(hHash, HP_HASHVAL, pbMac, &cbMac, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); SP_RETURN(PCT_INT_INTERNAL_ERROR); }
CryptDestroyHash(hHash);
return PCT_ERR_OK; }
//+---------------------------------------------------------------------------
//
// Function: Ssl2EncryptMessage
//
// Synopsis: Encode a block of data as an SSL2 record.
//
// Arguments: [pContext] -- Schannel context.
// [pAppInput] -- Data to be encrypted.
// [pCommOutput] -- (output) Completed SSL2 record.
//
// History: 10-22-97 jbanes CAPI integrated.
//
// Notes: An SSL2 record is usually formatted as:
//
// BYTE header[2];
// BYTE mac[mac_size];
// BYTE data[pAppInput->cbData];
//
// If a block cipher is used, and the data to be encrypted
// consists of a partial number of blocks, then the following
// format is used:
//
// BYTE header[3];
// BYTE mac[mac_size];
// BYTE data[pAppInput->cbData];
// BYTE padding[padding_size];
//
//----------------------------------------------------------------------------
SP_STATUS WINAPI Ssl2EncryptMessage( PSPContext pContext, PSPBuffer pAppInput, PSPBuffer pCommOutput) { SP_STATUS pctRet; DWORD cPadding; SPBuffer Clean; SPBuffer Encrypted;
SP_BEGIN("Ssl2EncryptMessage");
/* Estimate if we have padding or not */ Encrypted.cbData = pAppInput->cbData + pContext->pHashInfo->cbCheckSum; cPadding = (Encrypted.cbData % pContext->pCipherInfo->dwBlockSize); if(cPadding) { cPadding = pContext->pCipherInfo->dwBlockSize - cPadding; }
Encrypted.cbData += cPadding;
if(cPadding) { if(pCommOutput->cbBuffer + Encrypted.cbData + cPadding < 3) { SP_RETURN(SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL)); } Encrypted.pvBuffer = (PUCHAR)pCommOutput->pvBuffer + 3; Encrypted.cbBuffer = pCommOutput->cbBuffer - 3; } else { if(pCommOutput->cbBuffer + Encrypted.cbData + cPadding < 2) { SP_RETURN(SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL)); } Encrypted.pvBuffer = (PUCHAR)pCommOutput->pvBuffer + 2; Encrypted.cbBuffer = pCommOutput->cbBuffer - 2; } DebugLog((DEB_TRACE, "Sealing message %x\n", pContext->WriteCounter));
/* Move data out of the way if necessary */ if((PUCHAR)Encrypted.pvBuffer + pContext->pHashInfo->cbCheckSum != pAppInput->pvBuffer) { DebugLog((DEB_WARN, "SSL2EncryptMessage: Unnecessary Move, performance hog\n")); /* if caller wasn't being smart, then we must copy memory here */ MoveMemory((PUCHAR)Encrypted.pvBuffer + pContext->pHashInfo->cbCheckSum, pAppInput->pvBuffer, pAppInput->cbData); }
// Initialize pad
if(cPadding) { FillMemory((PUCHAR)Encrypted.pvBuffer + pContext->pHashInfo->cbCheckSum + pAppInput->cbData, cPadding, 0); }
// Compute MAC.
Clean.pvBuffer = (PBYTE)Encrypted.pvBuffer + pContext->pHashInfo->cbCheckSum; Clean.cbData = Encrypted.cbData - pContext->pHashInfo->cbCheckSum; Clean.cbBuffer = Clean.cbData;
pctRet = Ssl2ComputeMac(pContext, TRUE, pContext->WriteCounter, &Clean, Encrypted.pvBuffer, pContext->pHashInfo->cbCheckSum); if(pctRet != PCT_ERR_OK) { SP_RETURN(pctRet); }
// Encrypt buffer.
if(!CryptEncrypt(pContext->hWriteKey, 0, FALSE, 0, Encrypted.pvBuffer, &Encrypted.cbData, Encrypted.cbBuffer)) { SP_LOG_RESULT(GetLastError()); SP_RETURN(PCT_INT_INTERNAL_ERROR); }
/* set sizes */ if(cPadding) { if(Encrypted.cbData > 0x3fff) { SP_RETURN(SP_LOG_RESULT(PCT_INT_DATA_OVERFLOW)); }
((PUCHAR)pCommOutput->pvBuffer)[0]= (UCHAR)(0x3f & (Encrypted.cbData>>8)); ((PUCHAR)pCommOutput->pvBuffer)[1]= (UCHAR)(0xff & Encrypted.cbData); ((PUCHAR)pCommOutput->pvBuffer)[2]= (UCHAR)cPadding;
} else { if(Encrypted.cbData > 0x7fff) { SP_RETURN(SP_LOG_RESULT(PCT_INT_DATA_OVERFLOW)); } ((PUCHAR)pCommOutput->pvBuffer)[0]= (UCHAR)(0x7f & (Encrypted.cbData>>8)) | 0x80; ((PUCHAR)pCommOutput->pvBuffer)[1]= (UCHAR)(0xff & Encrypted.cbData); }
pCommOutput->cbData = Encrypted.cbData + (cPadding?3:2);
pContext->WriteCounter ++ ;
SP_RETURN( PCT_ERR_OK ); }
SP_STATUS WINAPI Ssl2GetHeaderSize( PSPContext pContext, PSPBuffer pCommInput, DWORD * pcbHeaderSize) { if(pcbHeaderSize == NULL) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); } if(pCommInput->cbData < 1) { return (PCT_INT_INCOMPLETE_MSG); } if( ((PUCHAR)pCommInput->pvBuffer)[0]&0x80 ) { *pcbHeaderSize = 2 + pContext->pHashInfo->cbCheckSum; } else { *pcbHeaderSize = 3 + pContext->pHashInfo->cbCheckSum; } return PCT_ERR_OK; }
//+---------------------------------------------------------------------------
//
// Function: Ssl2DecryptMessage
//
// Synopsis: Decode an SSL2 record.
//
// Arguments: [pContext] -- Schannel context.
// [pMessage] -- Data from the remote party.
// [pAppOutput] -- (output) Decrypted data.
//
// History: 10-22-97 jbanes CAPI integrated.
//
// Notes: An SSL2 record is usually formatted as:
//
// BYTE header[2];
// BYTE mac[mac_size];
// BYTE data[pAppInput->cbData];
//
// If a block cipher is used, and the data to be encrypted
// consists of a partial number of blocks, then the following
// format is used:
//
// BYTE header[3];
// BYTE mac[mac_size];
// BYTE data[pAppInput->cbData];
// BYTE padding[padding_size];
//
// The number of input data bytes consumed by this function
// is returned in pMessage->cbData.
//
//----------------------------------------------------------------------------
SP_STATUS WINAPI Ssl2DecryptMessage( PSPContext pContext, PSPBuffer pMessage, PSPBuffer pAppOutput) { SP_STATUS pctRet; DWORD cPadding; DWORD dwLength; SPBuffer Encrypted; SPBuffer Clean; DWORD cbActualData; UCHAR Digest[SP_MAX_DIGEST_LEN];
SP_BEGIN("Ssl2DecryptMessage");
/* 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 = 2; /* minimum amount of data we need */ if(pMessage->cbData > cbActualData) { SP_RETURN(PCT_INT_INCOMPLETE_MSG); } DebugLog((DEB_TRACE, " Incomming Buffer: %lx, size %ld (%lx)\n", pMessage->pvBuffer, cbActualData, cbActualData));
if(((PUCHAR)pMessage->pvBuffer)[0] & 0x80) { /* 2 byte header */ cPadding = 0; dwLength = ((((PUCHAR)pMessage->pvBuffer)[0] & 0x7f) << 8) | ((PUCHAR)pMessage->pvBuffer)[1];
Encrypted.pvBuffer = (PUCHAR)pMessage->pvBuffer + 2; Encrypted.cbBuffer = pMessage->cbBuffer - 2; } else { pMessage->cbData++; if(pMessage->cbData > cbActualData) { SP_RETURN(PCT_INT_INCOMPLETE_MSG); }
/* 3 byte header */ cPadding = ((PUCHAR)pMessage->pvBuffer)[2]; dwLength = ((((PUCHAR)pMessage->pvBuffer)[0] & 0x3f) << 8) | ((PUCHAR)pMessage->pvBuffer)[1];
Encrypted.pvBuffer = (PUCHAR)pMessage->pvBuffer + 3; Encrypted.cbBuffer = pMessage->cbBuffer - 3; }
/* Now we know how mutch data we will eat, so set cbData on the Input to be that size */ pMessage->cbData += dwLength;
/* do we have enough bytes for the reported data */ if(pMessage->cbData > cbActualData) { SP_RETURN(PCT_INT_INCOMPLETE_MSG); }
/* do we have enough data for our checksum */ if(dwLength < pContext->pHashInfo->cbCheckSum + cPadding) { SP_RETURN(SP_LOG_RESULT(PCT_INT_MSG_ALTERED)); }
Encrypted.cbData = dwLength; /* encrypted data size */ Encrypted.cbBuffer = Encrypted.cbData;
/* check to see if we have a block size violation */ if(Encrypted.cbData % pContext->pCipherInfo->dwBlockSize) { SP_RETURN(SP_LOG_RESULT(PCT_INT_MSG_ALTERED)); }
/* Decrypt */ if(!CryptDecrypt(pContext->hReadKey, 0, FALSE, 0, Encrypted.pvBuffer, &Encrypted.cbData)) { SP_LOG_RESULT(GetLastError()); SP_RETURN(PCT_INT_INTERNAL_ERROR); }
// Compute MAC.
Clean.pvBuffer = (PBYTE)Encrypted.pvBuffer + pContext->pHashInfo->cbCheckSum; Clean.cbData = Encrypted.cbData - pContext->pHashInfo->cbCheckSum; Clean.cbBuffer = Clean.cbData;
pctRet = Ssl2ComputeMac(pContext, FALSE, pContext->ReadCounter, &Clean, Digest, sizeof(Digest)); if(pctRet != PCT_ERR_OK) { SP_RETURN(pctRet); }
// the padding is computed in the hash but is not needed after this
Clean.cbData -= cPadding;
DebugLog((DEB_TRACE, "Unsealing message %x\n", pContext->ReadCounter));
pContext->ReadCounter++;
if(memcmp(Digest, Encrypted.pvBuffer, pContext->pHashInfo->cbCheckSum ) ) { SP_RETURN(SP_LOG_RESULT(PCT_INT_MSG_ALTERED)); }
if(pAppOutput->pvBuffer != Clean.pvBuffer) { DebugLog((DEB_WARN, "SSL2DecryptMessage: Unnecessary Move, performance hog\n")); MoveMemory(pAppOutput->pvBuffer, Clean.pvBuffer, Clean.cbData); } pAppOutput->cbData = Clean.cbData; DebugLog((DEB_TRACE, " TotalData: size %ld (%lx)\n", pMessage->cbData, pMessage->cbData));
SP_RETURN( PCT_ERR_OK ); }
#if 0
SP_STATUS Ssl2MakeMasterKeyBlock(PSPContext pContext) {
MD5_CTX Md5Hash; UCHAR cSalt; UCHAR ib;
//pContext->RipeZombe->pMasterKey containst the master secret.
#if DBG
DebugLog((DEB_TRACE, " Master Secret\n")); DBG_HEX_STRING(DEB_TRACE,pContext->RipeZombie->pMasterKey, pContext->RipeZombie->cbMasterKey);
#endif
for(ib=0 ; ib<3 ; ib++) { // MD5(master_secret + SHA-hash)
MD5Init (&Md5Hash); MD5Update(&Md5Hash, pContext->RipeZombie->pMasterKey, pContext->RipeZombie->cbMasterKey);
// We're going to be bug-for-bug compatable with netscape, so
// we always add the digit into the hash, instead of following
// the spec which says don't add the digit for DES
//if(pContext->RipeZombie->aiCipher != CALG_DES)
{ cSalt = ib+'0'; MD5Update(&Md5Hash, &cSalt, 1); } MD5Update(&Md5Hash, pContext->pChallenge, pContext->cbChallenge); MD5Update(&Md5Hash, pContext->pConnectionID, pContext->cbConnectionID); MD5Final (&Md5Hash); CopyMemory(pContext->Ssl3MasterKeyBlock + ib * MD5DIGESTLEN, Md5Hash.digest, MD5DIGESTLEN); } #if DBG
DebugLog((DEB_TRACE, " Master Key Block\n")); DBG_HEX_STRING(DEB_TRACE,pContext->Ssl3MasterKeyBlock, MD5DIGESTLEN*3);
#endif
return( PCT_ERR_OK ); } #endif
|