windows-nt/Source/XPSP1/NT/ds/security/protocols/schannel/spbase/pct1msg.c

1345 lines
40 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: pct1msg.c
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 09-23-97 jbanes LSA integration stuff.
//
//----------------------------------------------------------------------------
#include <spbase.h>
#include <pct1msg.h>
#include <pct1prot.h>
static SP_STATUS
Pct1ComputeMac(
PSPContext pContext,
BOOL fWriteMAC,
PSPBuffer pData,
DWORD dwSequence,
PBYTE pbMac,
PDWORD pcbMac);
Pct1CipherMap Pct1CipherRank[] = {
{CALG_RC4, 128, PCT1_CIPHER_RC4 | PCT1_ENC_BITS_128 | PCT1_MAC_BITS_128},
{CALG_RC4, 64, PCT1_CIPHER_RC4 | PCT1_ENC_BITS_64 | PCT1_MAC_BITS_128},
{CALG_RC4, 40, PCT1_CIPHER_RC4 | PCT1_ENC_BITS_40 | PCT1_MAC_BITS_128},
};
DWORD Pct1NumCipher = sizeof(Pct1CipherRank)/sizeof(Pct1CipherMap);
/* available hashes, in order of preference */
Pct1HashMap Pct1HashRank[] = {
{CALG_MD5, PCT1_HASH_MD5},
{CALG_SHA, PCT1_HASH_SHA}
};
DWORD Pct1NumHash = sizeof(Pct1HashRank)/sizeof(Pct1HashMap);
CertTypeMap aPct1CertEncodingPref[] =
{
{ X509_ASN_ENCODING , PCT1_CERT_X509_CHAIN },
{ X509_ASN_ENCODING , PCT1_CERT_X509 }
};
DWORD cPct1CertEncodingPref = sizeof(aPct1CertEncodingPref)/sizeof(CertTypeMap);
KeyTypeMap aPct1LocalExchKeyPref[] = // CAPI Key type, SCHANNEL ALGID
{
{ CALG_RSA_KEYX, SP_EXCH_RSA_PKCS1 }
};
DWORD cPct1LocalExchKeyPref = sizeof(aPct1LocalExchKeyPref)/sizeof(KeyTypeMap);
KeyTypeMap aPct1LocalSigKeyPref[] = // CAPI Key type, SCHANNEL ALGID
{
{ CALG_RSA_KEYX, SP_SIG_RSA_MD5 },
{ CALG_RSA_KEYX, SP_SIG_RSA_SHA }
};
DWORD cPct1LocalSigKeyPref = sizeof(aPct1LocalSigKeyPref)/sizeof(KeyTypeMap);
SP_STATUS WINAPI
Pct1EncryptRaw( PSPContext pContext,
PSPBuffer pAppInput,
PSPBuffer pCommOutput,
DWORD dwFlags)
{
SP_STATUS pctRet;
DWORD cPadding;
SPBuffer Clean;
SPBuffer Encrypted;
BOOL fEscape;
DWORD cbHeader;
DWORD cbBlockSize;
BYTE rgbMac[SP_MAX_DIGEST_LEN];
DWORD cbMac;
fEscape = (0 != (dwFlags & PCT1_ENCRYPT_ESCAPE));
cbBlockSize = pContext->pCipherInfo->dwBlockSize;
cPadding = pAppInput->cbData & (cbBlockSize - 1);
if(cPadding)
{
cPadding = cbBlockSize - cPadding;
}
if(fEscape || (cbBlockSize > 1))
{
cbHeader = sizeof(PCT1_MESSAGE_HEADER_EX);
}
else
{
cbHeader = sizeof(PCT1_MESSAGE_HEADER);
}
if(pCommOutput->cbBuffer < (cbHeader + cPadding + pAppInput->cbData))
{
return PCT_INT_BUFF_TOO_SMALL;
}
Encrypted.pvBuffer = (PUCHAR)pCommOutput->pvBuffer + cbHeader;
Encrypted.cbBuffer = pCommOutput->cbBuffer - cbHeader;
Encrypted.cbData = pAppInput->cbData;
// Copy input data to output buffer (we're encrypting in place).
if(pAppInput->pvBuffer != Encrypted.pvBuffer)
{
DebugLog((DEB_WARN, "Pct1EncryptRaw: Unnecessary Move, performance hog\n"));
MoveMemory(Encrypted.pvBuffer,
pAppInput->pvBuffer,
pAppInput->cbData);
}
/* Generate Padding */
GenerateRandomBits((PUCHAR)Encrypted.pvBuffer + Encrypted.cbData, cPadding);
Encrypted.cbData += cPadding;
DebugLog((DEB_TRACE, "Sealing message %x\n", pContext->WriteCounter));
// Transfer the write key over from the application process.
if(pContext->hWriteKey == 0)
{
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 the MAC.
cbMac = sizeof(rgbMac);
pctRet = Pct1ComputeMac(pContext,
TRUE,
&Encrypted,
pContext->WriteCounter,
rgbMac,
&cbMac);
if(pctRet != PCT_ERR_OK)
{
return SP_LOG_RESULT(pctRet);
}
pContext->WriteCounter ++ ;
// Encrypt data.
if(!SchCryptEncrypt(pContext->hWriteKey,
0, FALSE, 0,
Encrypted.pvBuffer,
&Encrypted.cbData,
Encrypted.cbBuffer,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
return PCT_INT_INTERNAL_ERROR;
}
// Add MAC to encrypted buffer.
if(Encrypted.cbData + cbMac > Encrypted.cbBuffer)
{
return PCT_INT_BUFF_TOO_SMALL;
}
CopyMemory((PUCHAR)Encrypted.pvBuffer + Encrypted.cbData,
rgbMac,
cbMac);
Encrypted.cbData += cbMac;
/* set sizes */
if(fEscape || (cbBlockSize > 1))
{
if(Encrypted.cbData > 0x3fff)
{
return PCT_INT_DATA_OVERFLOW;
}
((PUCHAR)pCommOutput->pvBuffer)[0]= (UCHAR)(0x3f & (Encrypted.cbData>>8));
if(fEscape)
{
((PUCHAR)pCommOutput->pvBuffer)[0] |= 0x40;
}
((PUCHAR)pCommOutput->pvBuffer)[1]= (UCHAR)(0xff & Encrypted.cbData);
((PUCHAR)pCommOutput->pvBuffer)[2]= (UCHAR)cPadding;
}
else
{
if(Encrypted.cbData > 0x7fff)
{
return 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 + cbHeader;
#if DBG
{
DWORD di;
CHAR KeyDispBuf[SP_MAX_DIGEST_LEN*2+1];
for(di=0;di<cbMac;di++)
wsprintf(KeyDispBuf+(di*2), "%2.2x", rgbMac[di]);
DebugLog((DEB_TRACE, " Computed MAC\t%s\n", KeyDispBuf));
}
#endif
return PCT_ERR_OK;
}
SP_STATUS WINAPI
Pct1EncryptMessage( PSPContext pContext,
PSPBuffer pAppInput,
PSPBuffer pCommOutput)
{
return Pct1EncryptRaw(pContext, pAppInput, pCommOutput,0);
}
SP_STATUS WINAPI
Pct1GetHeaderSize(
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;
}
else
{
*pcbHeaderSize = 3;
}
return PCT_ERR_OK;
}
SP_STATUS WINAPI
Pct1DecryptMessage(PSPContext pContext,
PSPBuffer pMessage,
PSPBuffer pAppOutput)
{
SP_STATUS pctRet;
DWORD cbHeader;
DWORD cbPadding;
DWORD cbPayload;
DWORD cbActualData;
SPBuffer Encrypted;
PUCHAR pbMAC;
BYTE rgbMac[SP_MAX_DIGEST_LEN];
DWORD cbMac;
cbActualData = pMessage->cbData;
// Do we have a complete header?
pMessage->cbData = 2;
if(cbActualData < 2)
{
return PCT_INT_INCOMPLETE_MSG;
}
if(((PUCHAR)pMessage->pvBuffer)[0] & 0x80)
{
cbHeader = 2;
cbPadding = 0;
cbPayload = MAKEWORD(((PUCHAR)pMessage->pvBuffer)[1],
((PUCHAR)pMessage->pvBuffer)[0] & 0x7f);
}
else
{
// Do we still have a complete header?
cbHeader = 3;
pMessage->cbData++;
if(cbActualData < cbHeader)
{
return PCT_INT_INCOMPLETE_MSG;
}
cbPadding = ((PUCHAR)pMessage->pvBuffer)[2];
cbPayload = MAKEWORD(((PUCHAR)pMessage->pvBuffer)[1],
((PUCHAR)pMessage->pvBuffer)[0] & 0x3f);
}
// Do we have the complete message?
pMessage->cbData += cbPayload;
if(cbActualData < cbHeader + cbPayload)
{
return PCT_INT_INCOMPLETE_MSG;
}
/* do we have enough data for our checksum */
if(cbPayload < pContext->pHashInfo->cbCheckSum)
{
return SP_LOG_RESULT(PCT_INT_MSG_ALTERED);
}
Encrypted.pvBuffer = (PUCHAR)pMessage->pvBuffer + cbHeader;
Encrypted.cbBuffer = cbPayload - pContext->pHashInfo->cbCheckSum;
Encrypted.cbData = Encrypted.cbBuffer;
pbMAC = (PUCHAR)Encrypted.pvBuffer + Encrypted.cbData;
/* check to see if we have a block size violation */
if(Encrypted.cbData % pContext->pCipherInfo->dwBlockSize)
{
return SP_LOG_RESULT(PCT_INT_MSG_ALTERED);
}
Encrypted.cbBuffer = Encrypted.cbData;
// Decrypt message.
if(Encrypted.cbData > pAppOutput->cbBuffer)
{
return SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL);
}
if(Encrypted.pvBuffer != pAppOutput->pvBuffer)
{
DebugLog((DEB_WARN, "Pct1DecryptMessage: Unnecessary MoveMemory, performance hog\n"));
MoveMemory(pAppOutput->pvBuffer,
Encrypted.pvBuffer,
Encrypted.cbData);
}
pAppOutput->cbData = Encrypted.cbData;
// Transfer the read key over from the application process.
if(pContext->hReadKey == 0)
{
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);
}
}
if(!SchCryptDecrypt(pContext->hReadKey,
0, FALSE, 0,
pAppOutput->pvBuffer,
&pAppOutput->cbData,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
return PCT_INT_INTERNAL_ERROR;
}
// Compute MAC
cbMac = sizeof(rgbMac);
pctRet = Pct1ComputeMac(pContext,
FALSE,
pAppOutput,
pContext->ReadCounter,
rgbMac,
&cbMac);
if(pctRet != PCT_ERR_OK)
{
return SP_LOG_RESULT(pctRet);
}
pContext->ReadCounter++;
#if DBG
{
DWORD di;
CHAR KeyDispBuf[SP_MAX_DIGEST_LEN*2+1];
for(di=0;di<pContext->pHashInfo->cbCheckSum;di++)
wsprintf(KeyDispBuf+(di*2), "%2.2x", pbMAC[di]);
DebugLog((DEB_TRACE, " Incoming MAC\t%s\n", KeyDispBuf));
for(di=0;di<cbMac;di++)
wsprintf(KeyDispBuf+(di*2), "%2.2x", rgbMac[di]);
DebugLog((DEB_TRACE, " Computed MAC\t%s\n", KeyDispBuf));
}
#endif
// Validate MAC
if (memcmp( rgbMac, pbMAC, cbMac ) )
{
return SP_LOG_RESULT(PCT_INT_MSG_ALTERED);
}
// Strip off the block cipher padding.
if(cbPadding > pAppOutput->cbData)
{
return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
}
pAppOutput->cbData -= cbPadding;
return( PCT_ERR_OK );
}
#if 0
SP_STATUS
PctComputeKey(PSPContext pContext,
PBYTE pKey,
DWORD cbKey,
PUCHAR pConst,
DWORD dwCLen,
DWORD fFlags)
{
DWORD pctRet;
HashBuf HBHash;
PCheckSumBuffer pHash;
PSessCacheItem pZombie=NULL;
PSPCredentialGroup pCred=NULL;
BYTE i,j;
DWORD iMax;
BYTE Buffer[MAX_CHECKSUM];
pZombie = pContext->RipeZombie;
pCred = pZombie ->pCred;
SP_BEGIN("PctComputeKey");
pHash = (PCheckSumBuffer)HBHash;
iMax = (cbKey + pContext->pHashInfo->cbCheckSum - 1)/pContext->pHashInfo->cbCheckSum;
if(iMax > 4)
{
SP_RETURN(PCT_INT_INTERNAL_ERROR);
}
for(i=1; i <= iMax; i++)
{
InitHashBuf(HBHash, pContext);
pContext->pHashInfo->System->Sum( pHash, 1, &i );
if (!(fFlags & PCT_MAKE_MAC))
{
// constant^i
pContext->pHashInfo->System->Sum( pHash, dwCLen*i, pConst);
}
// MASTER KEY
pContext->pHashInfo->System->Sum( pHash, pContext->RipeZombie->cbMasterKey, pContext->RipeZombie->pMasterKey);
// constant^i
pContext->pHashInfo->System->Sum( pHash, dwCLen*i, pConst);
// ConnectionID
pContext->pHashInfo->System->Sum( pHash, pContext->cbConnectionID, pContext->pConnectionID);
// constant^i
pContext->pHashInfo->System->Sum( pHash, dwCLen*i, pConst);
if (fFlags & PCT_USE_CERT)
{
/* add in the certificate */
pContext->pHashInfo->System->Sum( pHash, pZombie->cbServerCertificate, pZombie->pbServerCertificate );
// constant^i
pContext->pHashInfo->System->Sum( pHash, dwCLen*i, pConst);
}
// ConnectionID
pContext->pHashInfo->System->Sum( pHash, pContext->cbChallenge, pContext->pChallenge);
// constant^i
pContext->pHashInfo->System->Sum( pHash, dwCLen*i, pConst);
if(pContext->pHashInfo->cbCheckSum*i <= cbKey)
{
pContext->pHashInfo->System->Finalize( pHash, pKey + pContext->pHashInfo->cbCheckSum*(i-1) );
}
else
{
pContext->pHashInfo->System->Finalize( pHash, Buffer );
CopyMemory(pKey + pContext->pHashInfo->cbCheckSum*(i-1),
Buffer,
cbKey - pContext->pHashInfo->cbCheckSum*(i-1));
}
}
SP_RETURN(PCT_ERR_OK);
}
#endif
#if 0
SP_STATUS
PctComputeExportKey(PSPContext pContext,
PBYTE pKey,
DWORD cbWriteKey,
DWORD cbCipherKey)
{
DWORD pctRet;
HashBuf HBHash;
PCheckSumBuffer pHash;
PSessCacheItem pZombie=NULL;
PSPCredentialGroup pCred=NULL;
BYTE i,j;
DWORD d;
DWORD cbClearChunk;
BYTE pWriteKey[SP_MAX_MASTER_KEY];
BYTE Buffer[MAX_CHECKSUM];
pZombie = pContext->RipeZombie;
pCred = pZombie ->pCred;
SP_BEGIN("PctComputeKey");
pHash = (PCheckSumBuffer)HBHash;
CopyMemory(pWriteKey, pKey, cbWriteKey);
d = (cbCipherKey + pContext->pHashInfo->cbCheckSum - 1)/pContext->pHashInfo->cbCheckSum;
if(d > 4)
{
SP_RETURN(PCT_INT_INTERNAL_ERROR);
}
cbClearChunk = pContext->RipeZombie->cbClearKey/d;
for(i=1; i <= d; i++)
{
InitHashBuf(HBHash, pContext);
pContext->pHashInfo->System->Sum( pHash, 1, &i );
// constant^i
pContext->pHashInfo->System->Sum( pHash, PCT_CONST_SLK_LEN*i, PCT_CONST_SLK);
// WRITE_KEY
pContext->pHashInfo->System->Sum( pHash, cbWriteKey, pWriteKey);
// constant^i
pContext->pHashInfo->System->Sum( pHash, PCT_CONST_SLK_LEN*i, PCT_CONST_SLK);
// Clear Key
pContext->pHashInfo->System->Sum( pHash,
cbClearChunk,
(PBYTE)pContext->RipeZombie->pClearKey + (i-1)*cbClearChunk);
if(pContext->pHashInfo->cbCheckSum*i <= cbCipherKey)
{
pContext->pHashInfo->System->Finalize( pHash, pKey + pContext->pHashInfo->cbCheckSum*(i-1) );
}
else
{
pContext->pHashInfo->System->Finalize( pHash, Buffer );
CopyMemory(pKey + pContext->pHashInfo->cbCheckSum*(i-1),
Buffer,
cbCipherKey - pContext->pHashInfo->cbCheckSum*(i-1));
}
}
SP_RETURN(PCT_ERR_OK);
}
#endif
#if 0
SP_STATUS
Pct1MakeSessionKeys(
PSPContext pContext)
{
SP_STATUS pctRet;
BOOL fClient;
UCHAR pWriteKey[SP_MAX_MASTER_KEY], pReadKey[SP_MAX_MASTER_KEY];
#if DBG
DWORD i;
CHAR KeyDispBuf[SP_MAX_MASTER_KEY*2+1];
#endif
PSessCacheItem pZombie=NULL;
PSPCredentialGroup pCred=NULL;
SP_BEGIN("PctMakeSessionKeys");
pZombie = pContext->RipeZombie;
pCred = pZombie ->pCred;
if (!pContext->InitMACState)
{
SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
}
#if DBG
DebugLog((DEB_TRACE, "Making session keys\n", KeyDispBuf));
for(i=0;i<PCT_SESSION_ID_SIZE;i++)
wsprintf(KeyDispBuf+(i*2), "%2.2x",
pContext->pConnectionID[i]);
DebugLog((DEB_TRACE, " ConnId\t%s\n", KeyDispBuf));
for(i=0;i<PCT_CHALLENGE_SIZE;i++)
wsprintf(KeyDispBuf+(i*2), "%2.2x", (UCHAR)pContext->pChallenge[i]);
DebugLog((DEB_TRACE, " Challenge \t%s\n", KeyDispBuf));
for(i=0;i<pContext->RipeZombie->cbClearKey;i++)
wsprintf(KeyDispBuf+(i*2), "%2.2x", (UCHAR)pContext->RipeZombie->pClearKey[i]);
DebugLog((DEB_TRACE, " ClearKey \t%s\n", KeyDispBuf));
#endif
fClient = ((pContext->Flags & CONTEXT_FLAG_CLIENT) != 0);
pctRet = PctComputeKey( pContext, fClient?pWriteKey:pReadKey, pContext->pCipherInfo->cbSecret, PCT_CONST_CWK,
PCT_CONST_CWK_LEN, PCT_USE_CERT);
if(PCT_ERR_OK != pctRet)
{
goto quit;
}
pctRet = PctComputeKey( pContext, fClient?pReadKey:pWriteKey, pContext->pCipherInfo->cbSecret, PCT_CONST_SWK,
PCT_CONST_SWK_LEN, 0);
if(PCT_ERR_OK != pctRet)
{
goto quit;
}
/* compute the ClientMacKey */
pctRet = PctComputeKey(pContext,
(fClient?pContext->WriteMACKey:pContext->ReadMACKey),
pContext->pHashInfo->cbCheckSum,
PCT_CONST_CMK,
PCT_CONST_CMK_LEN,
PCT_USE_CERT | PCT_MAKE_MAC);
if(PCT_ERR_OK != pctRet)
{
goto quit;
}
/* compute the ServerMacKey */
pctRet = PctComputeKey(pContext,
(fClient?pContext->ReadMACKey:pContext->WriteMACKey),
pContext->pHashInfo->cbCheckSum,
PCT_CONST_SMK,
PCT_CONST_SMK_LEN,
PCT_MAKE_MAC);
if(PCT_ERR_OK != pctRet)
{
goto quit;
}
// Initialize the hash states
InitHashBuf(pContext->RdMACBuf, pContext);
InitHashBuf(pContext->WrMACBuf, pContext);
// Note, we truncuate the MACing keys down to the negotiated key size
pContext->ReadMACState = (PCheckSumBuffer)pContext->RdMACBuf;
pContext->pHashInfo->System->Sum( pContext->ReadMACState,
pContext->pHashInfo->cbCheckSum,
pContext->ReadMACKey);
pContext->WriteMACState = (PCheckSumBuffer)pContext->WrMACBuf;
pContext->pHashInfo->System->Sum( pContext->WriteMACState,
pContext->pHashInfo->cbCheckSum,
pContext->WriteMACKey);
if (pContext->pCipherInfo->cbSecret < pContext->pCipherInfo->cbKey)
{
pctRet = PctComputeExportKey(pContext,
pWriteKey,
pContext->pCipherInfo->cbSecret,
pContext->pCipherInfo->cbKey);
if(PCT_ERR_OK != pctRet)
{
goto quit;
}
pctRet = PctComputeExportKey(pContext,
pReadKey,
pContext->pCipherInfo->cbSecret,
pContext->pCipherInfo->cbKey);
if(PCT_ERR_OK != pctRet)
{
goto quit;
}
/* chop the encryption keys down to selected length */
}
#if DBG
for(i=0;i<pContext->RipeZombie->cbMasterKey;i++)
wsprintf(KeyDispBuf+(i*2), "%2.2x", pContext->RipeZombie->pMasterKey[i]);
DebugLog((DEB_TRACE, " MasterKey \t%s\n", KeyDispBuf));
for(i=0;i<pContext->pCipherInfo->cbKey;i++)
wsprintf(KeyDispBuf+(i*2), "%2.2x", pReadKey[i]);
DebugLog((DEB_TRACE, " ReadKey\t%s\n", KeyDispBuf));
for(i=0;i<pContext->pHashInfo->cbCheckSum;i++)
wsprintf(KeyDispBuf+(i*2), "%2.2x", pContext->ReadMACKey[i]);
DebugLog((DEB_TRACE, " MACKey\t%s\n", KeyDispBuf));
for(i=0;i<pContext->pCipherInfo->cbKey;i++)
wsprintf(KeyDispBuf+(i*2), "%2.2x", pWriteKey[i]);
DebugLog((DEB_TRACE, " WriteKey\t%s\n", KeyDispBuf));
for(i=0;i<pContext->pHashInfo->cbCheckSum;i++)
wsprintf(KeyDispBuf+(i*2), "%2.2x", pContext->WriteMACKey[i]);
DebugLog((DEB_TRACE, " MACKey\t%s\n", KeyDispBuf));
#endif
if (pContext->pCipherInfo->System->Initialize( pReadKey,
pContext->pCipherInfo->cbKey,
pZombie->pKeyArgs, // IV
pZombie->cbKeyArgs, // IV length
&pContext->pReadState ) )
{
if (pContext->pCipherInfo->System->Initialize( pWriteKey,
pContext->pCipherInfo->cbKey,
pZombie->pKeyArgs, // IV
pZombie->cbKeyArgs, // IV length
&pContext->pWriteState) )
{
pctRet = PCT_ERR_OK;
goto quit;
}
pctRet = SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
pContext->pCipherInfo->System->Discard( &pContext->pReadState );
}
pctRet = SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
quit:
SP_RETURN(pctRet);
}
#endif
SP_STATUS WINAPI Pct1DecryptHandler(PSPContext pContext,
PSPBuffer pCommInput,
PSPBuffer pAppOutput)
{
SP_STATUS pctRet= 0;
BOOL fEscape;
PPCT1_CLIENT_HELLO pHello;
if(pCommInput->cbData > 0) {
/* first, we'll handle incoming data packets */
if((pContext->State == SP_STATE_CONNECTED) && (pContext->Decrypt))
{
fEscape = (((*(PUCHAR)pCommInput->pvBuffer) & 0xc0) == 0x40);
/* BUGFIX: IE 3.0 and 3.0a incorrectly respond to a REDO request
* by just sending a PCT1 client hello, instead of another REDO.
* We therefore look at the incomming message and see if it
* looks like a PCT1 client hello.
*/
pHello = (PPCT1_CLIENT_HELLO)pCommInput->pvBuffer;
if((pCommInput->cbData >= 5) &&
(pHello->MessageId == PCT1_MSG_CLIENT_HELLO) &&
(pHello->VersionMsb == MSBOF(PCT_VERSION_1)) &&
(pHello->VersionLsb == LSBOF(PCT_VERSION_1)) &&
(pHello->OffsetMsb == MSBOF(PCT_CH_OFFSET_V1)) &&
(pHello->OffsetLsb == LSBOF(PCT_CH_OFFSET_V1)))
{
// This looks a lot like a client hello
/* InitiateRedo */
pAppOutput->cbData = 0;
pCommInput->cbData = 0;
pContext->State = PCT1_STATE_RENEGOTIATE;
;
return SP_LOG_RESULT(PCT_INT_RENEGOTIATE);
}
if(PCT_ERR_OK ==
(pctRet = pContext->Decrypt(pContext,
pCommInput, /* message */
pAppOutput /* Unpacked Message */
)))
{
/* look for escapes */
if(fEscape)
{
if(pAppOutput->cbData < 1)
{
return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
}
/* The first byte of the decrypt buffer is the escape code */
switch(*(PUCHAR)pAppOutput->pvBuffer)
{
case PCT1_ET_REDO_CONN:
{
/* InitiateRedo */
if(pAppOutput->cbData != 1)
{
return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
}
pContext->State = PCT1_STATE_RENEGOTIATE;
pAppOutput->cbData = 0;
return SP_LOG_RESULT(PCT_INT_RENEGOTIATE);
}
case PCT1_ET_OOB_DATA:
/* HandleOOB */
default:
/* Unknown escape, generate error */
pctRet = SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
/* Disconnect */
break;
}
}
}
return (pctRet);
}
else
{
return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG);
}
}
return PCT_INT_INCOMPLETE_MSG;
}
SP_STATUS Pct1GenerateError(PSPContext pContext,
PSPBuffer pCommOutput,
SP_STATUS pError,
PSPBuffer pErrData)
{
Pct1Error XmitError;
/* Only pack up an error if we are allowed to return errors */
if(!(pContext->Flags & CONTEXT_FLAG_EXT_ERR)) return pError;
XmitError.Error = pError;
XmitError.ErrInfoLen = 0;
XmitError.ErrInfo = NULL;
if(pErrData) {
XmitError.ErrInfoLen = pErrData->cbData;
XmitError.ErrInfo = pErrData->pvBuffer;
}
Pct1PackError(&XmitError,
pCommOutput);
return pError;
}
/* session key computation */
SP_STATUS Pct1HandleError(PSPContext pContext,
PSPBuffer pCommInput,
PSPBuffer pCommOutput)
{
pCommOutput->cbData = 0;
return(((PPCT1_ERROR)pCommInput->pvBuffer)->ErrorMsb << 8 )| ((PPCT1_ERROR)pCommInput->pvBuffer)->ErrorLsb;
}
//+---------------------------------------------------------------------------
//
// Function: Pct1BeginVerifyPrelude
//
// Synopsis: Initiate the "verify prelude" computation.
//
// Arguments: [pContext] -- Schannel context.
// [pClientHello] --
// [cbClientHello] --
// [pServerHello] --
// [cServerHello] --
//
// History: 10-10-97 jbanes Added CAPI integration.
//
// Notes: Hash(CLIENT_MAC_KEY, Hash("cvp", CLIENT_HELLO, SERVER_HELLO));
//
//----------------------------------------------------------------------------
SP_STATUS Pct1BeginVerifyPrelude(PSPContext pContext,
PUCHAR pClientHello,
DWORD cbClientHello,
PUCHAR pServerHello,
DWORD cbServerHello)
{
HCRYPTHASH hHash;
if(!SchCryptCreateHash(pContext->RipeZombie->hMasterProv,
pContext->pHashInfo->aiHash,
0,
0,
&hHash,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
return PCT_INT_INTERNAL_ERROR;
}
if(!SchCryptHashData(hHash,
PCT_CONST_VP,
PCT_CONST_VP_LEN,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
return PCT_INT_INTERNAL_ERROR;
}
if(!SchCryptHashData(hHash,
pClientHello,
cbClientHello,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
return PCT_INT_INTERNAL_ERROR;
}
if(!SchCryptHashData(hHash,
pServerHello,
cbServerHello,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
return PCT_INT_INTERNAL_ERROR;
}
pContext->hMd5Handshake = hHash;
return PCT_ERR_OK;
}
//+---------------------------------------------------------------------------
//
// Function: Pct1EndVerifyPrelude
//
// Synopsis: Finish the "verify prelude" computation.
//
// Arguments: [pContext] -- Schannel context.
// [VerifyPrelude] --
// [pcbVerifyPrelude] --
//
// History: 10-10-97 jbanes Added CAPI integration.
//
// Notes:
//
//----------------------------------------------------------------------------
SP_STATUS Pct1EndVerifyPrelude(PSPContext pContext,
PUCHAR VerifyPrelude,
DWORD * pcbVerifyPrelude)
{
BOOL fClient;
HCRYPTHASH hHash;
fClient = !(pContext->RipeZombie->fProtocol & SP_PROT_SERVERS);
if(!SchCryptGetHashParam(pContext->hMd5Handshake,
HP_HASHVAL,
VerifyPrelude,
pcbVerifyPrelude,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
SchCryptDestroyHash(pContext->hMd5Handshake, pContext->RipeZombie->dwCapiFlags);
pContext->hMd5Handshake = 0;
return PCT_INT_INTERNAL_ERROR;
}
SchCryptDestroyHash(pContext->hMd5Handshake, pContext->RipeZombie->dwCapiFlags);
pContext->hMd5Handshake = 0;
if(!SchCryptCreateHash(pContext->RipeZombie->hMasterProv,
pContext->pHashInfo->aiHash,
0,
0,
&hHash,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
return PCT_INT_INTERNAL_ERROR;
}
if(!SchCryptHashSessionKey(hHash,
fClient ? pContext->hWriteMAC : pContext->hReadMAC,
CRYPT_LITTLE_ENDIAN,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
return PCT_INT_INTERNAL_ERROR;
}
if(!SchCryptHashData(hHash,
VerifyPrelude,
*pcbVerifyPrelude,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
return PCT_INT_INTERNAL_ERROR;
}
if(!SchCryptGetHashParam(hHash,
HP_HASHVAL,
VerifyPrelude,
pcbVerifyPrelude,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
return PCT_INT_INTERNAL_ERROR;
}
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
return PCT_ERR_OK;
}
//+---------------------------------------------------------------------------
//
// Function: Pct1ComputeMac
//
// Synopsis: Compute the
//
// Arguments: [pContext] -- Schannel context.
//
// History: 10-10-97 jbanes Created.
//
// Notes: MAC_DATA := Hash(MAC_KEY, Hash(RECORD_HEADER_DATA,
// ACTUAL_DATA, PADDING_DATA, SEQUENCE_NUMBER))
//
//----------------------------------------------------------------------------
static SP_STATUS
Pct1ComputeMac(
PSPContext pContext, // in
BOOL fWriteMAC, // in
PSPBuffer pData, // in
DWORD dwSequence, // in
PBYTE pbMac, // out
PDWORD pcbMac) // in, out
{
HCRYPTHASH hHash;
DWORD dwReverseSequence;
dwReverseSequence = htonl(dwSequence);
// Compute inner hash
if(!SchCryptCreateHash(pContext->RipeZombie->hMasterProv,
pContext->pHashInfo->aiHash,
0,
0,
&hHash,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
return PCT_INT_INTERNAL_ERROR;
}
if(!SchCryptHashData(hHash,
pData->pvBuffer,
pData->cbData,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
CryptDestroyHash(hHash);
return PCT_INT_INTERNAL_ERROR;
}
if(!SchCryptHashData(hHash,
(PUCHAR)&dwReverseSequence,
sizeof(DWORD),
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
return PCT_INT_INTERNAL_ERROR;
}
if(!SchCryptGetHashParam(hHash,
HP_HASHVAL,
pbMac,
pcbMac,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
return PCT_INT_INTERNAL_ERROR;
}
SP_ASSERT(*pcbMac == pContext->pHashInfo->cbCheckSum);
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
// Compute outer hash.
if(!SchCryptCreateHash(pContext->RipeZombie->hMasterProv,
pContext->pHashInfo->aiHash,
0,
0,
&hHash,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
return PCT_INT_INTERNAL_ERROR;
}
if(!SchCryptHashSessionKey(hHash,
fWriteMAC ? pContext->hWriteMAC : pContext->hReadMAC,
CRYPT_LITTLE_ENDIAN,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
return PCT_INT_INTERNAL_ERROR;
}
if(!SchCryptHashData(hHash, pbMac, *pcbMac, 0, pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
return PCT_INT_INTERNAL_ERROR;
}
if(!SchCryptGetHashParam(hHash,
HP_HASHVAL,
pbMac,
pcbMac,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
return PCT_INT_INTERNAL_ERROR;
}
SP_ASSERT(*pcbMac == pContext->pHashInfo->cbCheckSum);
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
return PCT_ERR_OK;
}
//+---------------------------------------------------------------------------
//
// Function: Pct1ComputeResponse
//
// Synopsis: Compute the "response" field of the ServerVerify message.
//
// Arguments: [pContext] -- Schannel context.
// [pbChallenge] --
// [cbChallenge] --
// [pbConnectionID] --
// [cbConnectionID] --
// [pbSessionID] --
// [cbSessionID] --
// [pbResponse] --
// [pcbResponse] --
//
// History: 10-10-97 jbanes Created.
//
// Notes: Hash(SERVER_MAC_KEY, Hash ("sr", CH_CHALLENGE_DATA,
// SH_CONNECTION_ID_DATA, SV_SESSION_ID_DATA))
//
//----------------------------------------------------------------------------
SP_STATUS
Pct1ComputeResponse(
PSPContext pContext, // in
PBYTE pbChallenge, // in
DWORD cbChallenge, // in
PBYTE pbConnectionID, // in
DWORD cbConnectionID, // in
PBYTE pbSessionID, // in
DWORD cbSessionID, // in
PBYTE pbResponse, // out
PDWORD pcbResponse) // in, out
{
BOOL fClient;
HCRYPTHASH hHash = 0;
SP_STATUS pctRet;
fClient = !(pContext->RipeZombie->fProtocol & SP_PROT_SERVERS);
//
// Hash ("sr", CH_CHALLENGE_DATA, SH_CONNECTION_ID_DATA,
// SV_SESSION_ID_DATA). Place the result in pbResponse.
//
if(!SchCryptCreateHash(pContext->RipeZombie->hMasterProv,
pContext->pHashInfo->aiHash,
0,
0,
&hHash,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_INT_INTERNAL_ERROR;
goto cleanup;
}
if(!SchCryptHashData(hHash,
PCT_CONST_RESP,
PCT_CONST_RESP_LEN,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_INT_INTERNAL_ERROR;
goto cleanup;
}
if(!SchCryptHashData(hHash,
pbChallenge,
cbChallenge,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_INT_INTERNAL_ERROR;
goto cleanup;
}
if(!SchCryptHashData(hHash,
pbConnectionID,
cbConnectionID,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_INT_INTERNAL_ERROR;
goto cleanup;
}
if(!SchCryptHashData(hHash,
pbSessionID,
cbSessionID,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_INT_INTERNAL_ERROR;
goto cleanup;
}
if(!SchCryptGetHashParam(hHash,
HP_HASHVAL,
pbResponse,
pcbResponse,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_INT_INTERNAL_ERROR;
goto cleanup;
}
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
hHash = 0;
//
// Hash (SERVER_MAC_KEY, pbResponse). Place the result back in pbResponse.
//
if(!SchCryptCreateHash(pContext->RipeZombie->hMasterProv,
pContext->pHashInfo->aiHash,
0,
0,
&hHash,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_INT_INTERNAL_ERROR;
goto cleanup;
}
if(!SchCryptHashSessionKey(hHash,
fClient ? pContext->hReadMAC : pContext->hWriteMAC,
CRYPT_LITTLE_ENDIAN,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_INT_INTERNAL_ERROR;
goto cleanup;
}
if(!SchCryptHashData(hHash,
pbResponse,
*pcbResponse,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_INT_INTERNAL_ERROR;
goto cleanup;
}
if(!SchCryptGetHashParam(hHash,
HP_HASHVAL,
pbResponse,
pcbResponse,
0,
pContext->RipeZombie->dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_INT_INTERNAL_ERROR;
goto cleanup;
}
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
hHash = 0;
pctRet = PCT_ERR_OK;
cleanup:
if(hHash)
{
SchCryptDestroyHash(hHash, pContext->RipeZombie->dwCapiFlags);
}
return pctRet;
}