mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1197 lines
32 KiB
1197 lines
32 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1995.
|
|
//
|
|
// File: pickle.c
|
|
//
|
|
// Contents:
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 8-02-95 RichardW Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "pctsspi.h"
|
|
|
|
// internal allocation failure codes.
|
|
|
|
#define AF_NONE 0
|
|
#define AF_CIPHER 1
|
|
#define AF_HASH 2
|
|
#define AF_CERT 3
|
|
#define AF_EXCH 4
|
|
|
|
#define SIZEOF(pMessage) (PctRecordSize((PPct_Record_Header) pMessage ) )
|
|
|
|
DWORD MapCipherToExternal(CipherSpec Internal, ExtCipherSpec *External)
|
|
{
|
|
*External = htonl(Internal);
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD MapHashToExternal(HashSpec Internal, ExtHashSpec *External)
|
|
{
|
|
*External = htons((ExtHashSpec)Internal);
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD MapCertToExternal(CertSpec Internal, ExtCertSpec *External)
|
|
{
|
|
*External = htons((ExtCertSpec)Internal);
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD MapExchToExternal(ExchSpec Internal, ExtExchSpec *External)
|
|
{
|
|
*External = htons((ExtExchSpec)Internal);
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD MapSigToExternal(SigSpec Internal, ExtSigSpec *External)
|
|
{
|
|
*External = htons((ExtSigSpec)Internal);
|
|
return TRUE;
|
|
}
|
|
|
|
CipherSpec MapCipherFromExternal(ExtCipherSpec External)
|
|
{
|
|
return (CipherSpec)ntohl(External);
|
|
}
|
|
|
|
HashSpec MapHashFromExternal(ExtHashSpec External)
|
|
{
|
|
return (HashSpec)ntohs(External);
|
|
}
|
|
|
|
CertSpec MapCertFromExternal(ExtCertSpec External)
|
|
{
|
|
return (CertSpec)ntohs(External);
|
|
}
|
|
|
|
ExchSpec MapExchFromExternal(ExtExchSpec External)
|
|
{
|
|
return (ExchSpec)ntohs(External);
|
|
}
|
|
|
|
SigSpec MapSigFromExternal(ExtSigSpec External)
|
|
{
|
|
return (SigSpec)ntohs(External);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
PctRecordSize(
|
|
PPct_Record_Header pHeader)
|
|
{
|
|
DWORD Size;
|
|
|
|
if (pHeader->Byte0 & 0x80)
|
|
{
|
|
Size = COMBINEBYTES(pHeader->Byte0, pHeader->Byte1) & 0x7FFF;
|
|
}
|
|
else
|
|
{
|
|
Size = COMBINEBYTES(pHeader->Byte0, pHeader->Byte1) & 0x3FFF;
|
|
}
|
|
return(Size);
|
|
}
|
|
|
|
BOOL
|
|
PackClientHello(
|
|
PClient_Hello pCanonical,
|
|
PPct_Client_Hello * ppNetwork,
|
|
DWORD * pcbNetwork)
|
|
{
|
|
DWORD TotalSpace;
|
|
DWORD MessageLength;
|
|
PPct_Client_Hello pMessage;
|
|
DWORD Size;
|
|
PUCHAR pBuffer;
|
|
DWORD i;
|
|
|
|
|
|
MessageLength = PCT_SESSION_ID_SIZE +
|
|
PCT_CHALLENGE_SIZE +
|
|
pCanonical->cCipherSpecs * sizeof(ExtCipherSpec) +
|
|
pCanonical->cHashSpecs * sizeof(ExtHashSpec) +
|
|
pCanonical->cCertSpecs * sizeof(ExtCertSpec) +
|
|
pCanonical->cExchSpecs * sizeof(ExtExchSpec) +
|
|
pCanonical->cbKeyArgSize +
|
|
sizeof(Pct_Client_Hello) -
|
|
(sizeof(Pct_Record_Header) + 1 );
|
|
|
|
if (MessageLength > PCT_MAX_SHAKE_LEN)
|
|
return FALSE;
|
|
|
|
TotalSpace = MessageLength + 2;
|
|
|
|
if ((!pcbNetwork) || (!ppNetwork))
|
|
return (FALSE);
|
|
|
|
if ((*ppNetwork) && (*pcbNetwork < TotalSpace))
|
|
{
|
|
*pcbNetwork = TotalSpace;
|
|
return(FALSE);
|
|
}
|
|
|
|
*pcbNetwork = TotalSpace;
|
|
|
|
if (*ppNetwork)
|
|
{
|
|
pMessage = *ppNetwork;
|
|
}
|
|
else
|
|
{
|
|
pMessage = PctExternalAlloc(TotalSpace);
|
|
if (!pMessage)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
pMessage->MessageId = PCT_MSG_CLIENT_HELLO;
|
|
|
|
pMessage->VersionMsb = MSBOF(PCT_VERSION_1);
|
|
pMessage->VersionLsb = LSBOF(PCT_VERSION_1);
|
|
|
|
pMessage->OffsetMsb = MSBOF(PCT_CH_OFFSET_V1);
|
|
pMessage->OffsetLsb = LSBOF(PCT_CH_OFFSET_V1);
|
|
|
|
CopyMemory( pMessage->SessionIdData,
|
|
(PUCHAR)pCanonical->SessionId.bSessionId,
|
|
PCT_SESSION_ID_SIZE);
|
|
|
|
CopyMemory( pMessage->ChallengeData,
|
|
pCanonical->Challenge.bChallenge,
|
|
PCT_CHALLENGE_SIZE);
|
|
|
|
pBuffer = pMessage->VariantData;
|
|
|
|
Size = pCanonical->cCipherSpecs * sizeof(ExtCipherSpec);
|
|
|
|
for (i = 0; i < pCanonical->cCipherSpecs ; i++ )
|
|
{
|
|
if (MapCipherToExternal(pCanonical->pCipherSpecs[i],
|
|
(ExtCipherSpec *) pBuffer) )
|
|
{
|
|
pBuffer += sizeof(ExtCipherSpec);
|
|
}
|
|
else
|
|
{
|
|
Size -= sizeof(ExtCipherSpec);
|
|
MessageLength -= sizeof(ExtCipherSpec);
|
|
TotalSpace -= sizeof(ExtCipherSpec);
|
|
}
|
|
}
|
|
|
|
pMessage->CipherSpecsLenMsb = MSBOF(Size);
|
|
pMessage->CipherSpecsLenLsb = LSBOF(Size);
|
|
|
|
Size = pCanonical->cHashSpecs * sizeof(ExtHashSpec);
|
|
|
|
for (i = 0; i < pCanonical->cHashSpecs ; i++ )
|
|
{
|
|
if (MapHashToExternal(pCanonical->pHashSpecs[i],
|
|
(ExtHashSpec *) pBuffer) )
|
|
{
|
|
pBuffer += sizeof(ExtHashSpec);
|
|
}
|
|
else
|
|
{
|
|
Size -= sizeof(ExtHashSpec);
|
|
MessageLength -= sizeof(ExtHashSpec);
|
|
TotalSpace -= sizeof(ExtHashSpec);
|
|
}
|
|
}
|
|
|
|
pMessage->HashSpecsLenMsb = MSBOF(Size);
|
|
pMessage->HashSpecsLenLsb = LSBOF(Size);
|
|
|
|
Size = pCanonical->cCertSpecs * sizeof(ExtCertSpec);
|
|
|
|
for (i = 0; i < pCanonical->cCertSpecs ; i++ )
|
|
{
|
|
if (MapCertToExternal(pCanonical->pCertSpecs[i],
|
|
(ExtCertSpec *) pBuffer) )
|
|
{
|
|
pBuffer += sizeof(ExtCertSpec);
|
|
}
|
|
else
|
|
{
|
|
Size -= sizeof(ExtCertSpec);
|
|
MessageLength -= sizeof(ExtCertSpec);
|
|
TotalSpace -= sizeof(ExtCertSpec);
|
|
}
|
|
}
|
|
|
|
pMessage->CertSpecsLenMsb = MSBOF(Size);
|
|
pMessage->CertSpecsLenLsb = LSBOF(Size);
|
|
|
|
Size = pCanonical->cExchSpecs * sizeof(ExtExchSpec);
|
|
|
|
for (i = 0; i < pCanonical->cExchSpecs ; i++ )
|
|
{
|
|
if (MapExchToExternal(pCanonical->pExchSpecs[i],
|
|
(ExtExchSpec *) pBuffer) )
|
|
{
|
|
pBuffer += sizeof(ExtExchSpec);
|
|
}
|
|
else
|
|
{
|
|
Size -= sizeof(ExtExchSpec);
|
|
MessageLength -= sizeof(ExtExchSpec);
|
|
TotalSpace -= sizeof(ExtExchSpec);
|
|
}
|
|
}
|
|
|
|
pMessage->ExchSpecsLenMsb = MSBOF(Size);
|
|
pMessage->ExchSpecsLenLsb = LSBOF(Size);
|
|
|
|
*pcbNetwork = TotalSpace;
|
|
|
|
pMessage->Header.Byte0 = MSBOF(MessageLength) | 0x80;
|
|
pMessage->Header.Byte1 = LSBOF(MessageLength);
|
|
|
|
*ppNetwork = pMessage;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL
|
|
UnpackClientHello(
|
|
BOOL SingleAlloc,
|
|
DWORD *ErrorInfo,
|
|
PPct_Client_Hello pMessage,
|
|
DWORD cbMessage,
|
|
PClient_Hello * ppClient)
|
|
{
|
|
DWORD ReportedSize;
|
|
DWORD CipherSpecsSize, HashSpecsSize, CertSpecsSize;
|
|
DWORD ExchSpecsSize;
|
|
DWORD cCipherSpecs, cHashSpecs, cCertSpecs, cExchSpecs;
|
|
PClient_Hello pCanonical;
|
|
PUCHAR pBuffer;
|
|
DWORD Size, dwAllocFail;
|
|
DWORD ValidRemainingSize;
|
|
DWORD i;
|
|
|
|
|
|
ReportedSize = SIZEOF(pMessage);
|
|
|
|
if (ReportedSize > cbMessage)
|
|
{
|
|
SetLastError((ULONG) SEC_E_INVALID_TOKEN);
|
|
return(FALSE);
|
|
}
|
|
|
|
*ppClient = NULL;
|
|
*ErrorInfo = 0;
|
|
|
|
if ((pMessage->VersionMsb & 0x80) == 0)
|
|
{
|
|
*ErrorInfo = PCT_ERR_SSL_STYLE_MSG;
|
|
return (FALSE);
|
|
}
|
|
|
|
if ((pMessage->MessageId != PCT_MSG_CLIENT_HELLO) ||
|
|
(pMessage->VersionMsb != MSBOF(PCT_VERSION_1)) ||
|
|
(pMessage->VersionLsb != LSBOF(PCT_VERSION_1)) )
|
|
{
|
|
SetLastError((ULONG) SEC_E_INVALID_TOKEN);
|
|
return(FALSE);
|
|
}
|
|
|
|
CipherSpecsSize = COMBINEBYTES( pMessage->CipherSpecsLenMsb,
|
|
pMessage->CipherSpecsLenLsb );
|
|
|
|
HashSpecsSize = COMBINEBYTES( pMessage->HashSpecsLenMsb,
|
|
pMessage->HashSpecsLenLsb );
|
|
|
|
CertSpecsSize = COMBINEBYTES( pMessage->CertSpecsLenMsb,
|
|
pMessage->CertSpecsLenLsb );
|
|
|
|
ExchSpecsSize = COMBINEBYTES( pMessage->ExchSpecsLenMsb,
|
|
pMessage->ExchSpecsLenLsb );
|
|
|
|
// check that this all fits into the message
|
|
if (((sizeof(Pct_Client_Hello)
|
|
- sizeof(Pct_Record_Header) // don't count the header
|
|
- sizeof(UCHAR)) // don't count the variant pointer
|
|
+ CipherSpecsSize
|
|
+ HashSpecsSize
|
|
+ CertSpecsSize
|
|
+ ExchSpecsSize) > ReportedSize)
|
|
return FALSE;
|
|
|
|
cCipherSpecs = CipherSpecsSize / sizeof(ExtCipherSpec);
|
|
cHashSpecs = HashSpecsSize / sizeof(ExtHashSpec);
|
|
cExchSpecs = ExchSpecsSize / sizeof(ExtExchSpec);
|
|
cCertSpecs = CertSpecsSize / sizeof(ExtCertSpec);
|
|
|
|
if (SingleAlloc)
|
|
{
|
|
pCanonical = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof(Client_Hello) +
|
|
cCipherSpecs * sizeof(CipherSpec) +
|
|
cHashSpecs * sizeof(HashSpec) +
|
|
cCertSpecs * sizeof(CertSpec) +
|
|
cExchSpecs * sizeof(ExchSpec));
|
|
|
|
if (!pCanonical)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
pCanonical->pCipherSpecs = (PCipherSpec) (pCanonical + 1);
|
|
pCanonical->pHashSpecs = (PHashSpec) (pCanonical->pCipherSpecs +
|
|
cCipherSpecs);
|
|
pCanonical->pCertSpecs = (PCertSpec) (pCanonical->pHashSpecs +
|
|
cHashSpecs);
|
|
pCanonical->pExchSpecs = (PExchSpec) (pCanonical->pCertSpecs +
|
|
cCertSpecs);
|
|
}
|
|
else
|
|
{
|
|
pCanonical = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof(Client_Hello) );
|
|
|
|
if (!pCanonical)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
dwAllocFail = AF_NONE;
|
|
|
|
if ((dwAllocFail == AF_NONE) &&
|
|
(pCanonical->pCipherSpecs = LocalAlloc(LMEM_FIXED,
|
|
cCipherSpecs * sizeof(CipherSpec))) ==
|
|
NULL)
|
|
{
|
|
dwAllocFail = AF_CIPHER;
|
|
}
|
|
|
|
if ((dwAllocFail == AF_NONE) &&
|
|
(pCanonical->pHashSpecs = LocalAlloc(LMEM_FIXED,
|
|
cHashSpecs * sizeof(HashSpec))) ==
|
|
NULL)
|
|
{
|
|
dwAllocFail = AF_HASH;
|
|
}
|
|
|
|
if ((dwAllocFail == AF_NONE) &&
|
|
(pCanonical->pCertSpecs = LocalAlloc(LMEM_FIXED,
|
|
cCertSpecs * sizeof(CertSpec))) ==
|
|
NULL)
|
|
{
|
|
dwAllocFail = AF_CERT;
|
|
}
|
|
|
|
if ((dwAllocFail == AF_NONE) &&
|
|
(pCanonical->pExchSpecs = LocalAlloc(LMEM_FIXED,
|
|
cExchSpecs * sizeof(ExchSpec))) ==
|
|
NULL)
|
|
{
|
|
dwAllocFail = AF_EXCH;
|
|
}
|
|
|
|
switch(dwAllocFail)
|
|
{
|
|
case AF_NONE:
|
|
break;
|
|
|
|
case AF_EXCH:
|
|
LocalFree(pCanonical->pExchSpecs);
|
|
|
|
case AF_CERT:
|
|
LocalFree(pCanonical->pCertSpecs);
|
|
|
|
case AF_HASH:
|
|
LocalFree(pCanonical->pHashSpecs);
|
|
|
|
case AF_CIPHER:
|
|
LocalFree(pCanonical->pCipherSpecs);
|
|
|
|
default:
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
CopyMemory( pCanonical->SessionId.bSessionId,
|
|
pMessage->SessionIdData, PCT_SESSION_ID_SIZE);
|
|
CopyMemory( pCanonical->Challenge.bChallenge,
|
|
pMessage->ChallengeData, PCT_CHALLENGE_SIZE );
|
|
|
|
pBuffer = pMessage->VariantData;
|
|
ValidRemainingSize = cbMessage - sizeof(Pct_Client_Hello) + 1;
|
|
|
|
pCanonical->cCipherSpecs = cCipherSpecs;
|
|
|
|
for (i = 0 ; i < cCipherSpecs ; i++ )
|
|
{
|
|
pCanonical->pCipherSpecs[i] = MapCipherFromExternal(*(ExtCipherSpec *)
|
|
pBuffer);
|
|
|
|
pBuffer += sizeof(ExtCipherSpec);
|
|
}
|
|
|
|
pCanonical->cHashSpecs = cHashSpecs;
|
|
|
|
for (i = 0 ; i < cHashSpecs ; i++ )
|
|
{
|
|
pCanonical->pHashSpecs[i] = MapHashFromExternal(*(ExtHashSpec *)
|
|
pBuffer);
|
|
|
|
pBuffer += sizeof(ExtHashSpec);
|
|
}
|
|
|
|
pCanonical->cCertSpecs = cCertSpecs;
|
|
|
|
for (i = 0 ; i < cCertSpecs ; i++ )
|
|
{
|
|
pCanonical->pCertSpecs[i] = MapCertFromExternal(*(ExtCertSpec *)
|
|
pBuffer);
|
|
|
|
pBuffer += sizeof(ExtCertSpec);
|
|
}
|
|
|
|
pCanonical->cExchSpecs = cExchSpecs;
|
|
|
|
for (i = 0 ; i < cExchSpecs ; i++ )
|
|
{
|
|
pCanonical->pExchSpecs[i] = MapExchFromExternal(*(ExtExchSpec *)
|
|
pBuffer);
|
|
|
|
pBuffer += sizeof(ExtExchSpec);
|
|
}
|
|
|
|
*ppClient = pCanonical;
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
BOOL
|
|
PackServerHello(
|
|
PServer_Hello pCanonical,
|
|
PPct_Server_Hello * ppNetwork,
|
|
DWORD * pcbNetwork)
|
|
{
|
|
DWORD TotalSpace;
|
|
DWORD MessageLength;
|
|
PPct_Server_Hello pMessage;
|
|
DWORD Size;
|
|
PUCHAR pBuffer;
|
|
DWORD i;
|
|
|
|
MessageLength = pCanonical->CertificateLen +
|
|
pCanonical->cCertSpecs * sizeof(ExtCertSpec) +
|
|
pCanonical->cSigSpecs * sizeof(ExtSigSpec) +
|
|
pCanonical->ResponseLen +
|
|
sizeof(Pct_Server_Hello) -
|
|
(sizeof(Pct_Record_Header) + 1 );
|
|
|
|
if (MessageLength > PCT_MAX_SHAKE_LEN)
|
|
return FALSE;
|
|
|
|
TotalSpace = MessageLength + 2;
|
|
|
|
if ((!pcbNetwork) || (!ppNetwork))
|
|
return (FALSE);
|
|
|
|
if ((*ppNetwork) && (*pcbNetwork < TotalSpace))
|
|
{
|
|
*pcbNetwork = TotalSpace;
|
|
return(FALSE);
|
|
}
|
|
|
|
*pcbNetwork = TotalSpace;
|
|
|
|
if (*ppNetwork)
|
|
{
|
|
pMessage = *ppNetwork;
|
|
}
|
|
else
|
|
{
|
|
pMessage = PctExternalAlloc( TotalSpace );
|
|
if (!pMessage)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
pMessage->MessageId = PCT_MSG_SERVER_HELLO;
|
|
pMessage->ServerVersionMsb = MSBOF(PCT_VERSION_1);
|
|
pMessage->ServerVersionLsb = LSBOF(PCT_VERSION_1);
|
|
pMessage->RestartSessionOK = (UCHAR) pCanonical->RestartOk;
|
|
pMessage->ClientAuthReq = (UCHAR)pCanonical->ClientAuthReq;
|
|
|
|
MapCipherToExternal(pCanonical->SrvCipherSpec, &pMessage->CipherSpecData);
|
|
MapHashToExternal(pCanonical->SrvHashSpec, &pMessage->HashSpecData);
|
|
MapCertToExternal(pCanonical->SrvCertSpec, &pMessage->CertSpecData);
|
|
MapExchToExternal(pCanonical->SrvExchSpec, &pMessage->ExchSpecData);
|
|
|
|
CopyMemory(pMessage->ConnectionIdData, pCanonical->Connection.bSessionId,
|
|
PCT_SESSION_ID_SIZE);
|
|
|
|
pBuffer = pMessage->VariantData;
|
|
|
|
//
|
|
// Pack certificate if present
|
|
//
|
|
|
|
pMessage->CertificateLenMsb = MSBOF(pCanonical->CertificateLen);
|
|
pMessage->CertificateLenLsb = LSBOF(pCanonical->CertificateLen);
|
|
|
|
if (pCanonical->CertificateLen)
|
|
{
|
|
CopyMemory( pBuffer,
|
|
pCanonical->pCertificate,
|
|
pCanonical->CertificateLen);
|
|
|
|
pBuffer += pCanonical->CertificateLen ;
|
|
}
|
|
|
|
Size = pCanonical->cCertSpecs * sizeof(ExtCertSpec);
|
|
|
|
for (i = 0; i < pCanonical->cCertSpecs ; i++ )
|
|
{
|
|
if (MapCertToExternal(pCanonical->pClientCertSpecs[i],
|
|
(PExtCertSpec) pBuffer) )
|
|
{
|
|
pBuffer += sizeof(ExtCertSpec);
|
|
}
|
|
else
|
|
{
|
|
Size -= sizeof(ExtCertSpec);
|
|
MessageLength -= sizeof(ExtCertSpec);
|
|
TotalSpace -= sizeof(ExtCertSpec);
|
|
}
|
|
}
|
|
|
|
pMessage->CertSpecsLenMsb = MSBOF(Size);
|
|
pMessage->CertSpecsLenLsb = LSBOF(Size);
|
|
|
|
Size = pCanonical->cSigSpecs * sizeof(ExtSigSpec);
|
|
|
|
for (i = 0; i < pCanonical->cSigSpecs ; i++ )
|
|
{
|
|
if (MapCertToExternal(pCanonical->pClientSigSpecs[i],
|
|
(PExtSigSpec) pBuffer) )
|
|
{
|
|
pBuffer += sizeof(ExtSigSpec);
|
|
}
|
|
else
|
|
{
|
|
Size -= sizeof(ExtSigSpec);
|
|
MessageLength -= sizeof(ExtSigSpec);
|
|
TotalSpace -= sizeof(ExtSigSpec);
|
|
}
|
|
}
|
|
|
|
pMessage->ClientSigSpecsLenMsb = MSBOF(Size);
|
|
pMessage->ClientSigSpecsLenLsb = LSBOF(Size);
|
|
|
|
*pcbNetwork = TotalSpace;
|
|
|
|
pMessage->Header.Byte0 = MSBOF(MessageLength) | 0x80;
|
|
pMessage->Header.Byte1 = LSBOF(MessageLength);
|
|
|
|
pMessage->ResponseLenMsb = MSBOF(pCanonical->ResponseLen);
|
|
pMessage->ResponseLenLsb = LSBOF(pCanonical->ResponseLen);
|
|
|
|
CopyMemory( pBuffer,
|
|
pCanonical->Response,
|
|
pCanonical->ResponseLen);
|
|
|
|
pBuffer += pCanonical->ResponseLen;
|
|
|
|
*ppNetwork = pMessage;
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
UnpackServerHello(
|
|
BOOL SingleAlloc,
|
|
DWORD *ErrorInfo,
|
|
PPct_Server_Hello pMessage,
|
|
DWORD cbMessage,
|
|
PServer_Hello * ppServer)
|
|
{
|
|
PServer_Hello pCanonical;
|
|
PPct_Error pError;
|
|
PUCHAR pBuffer;
|
|
DWORD cbCertificate, cbResponse;
|
|
DWORD cCertSpecs, cSigSpecs;
|
|
DWORD cbConnId;
|
|
DWORD i;
|
|
DWORD ReportedSize;
|
|
|
|
ReportedSize = SIZEOF(pMessage);
|
|
if (ReportedSize > cbMessage)
|
|
{
|
|
DebugLog((DEB_WARN, "ReportedSize (%d, %#x) > actual size (%d, %#x)\n",
|
|
ReportedSize, ReportedSize, cbMessage, cbMessage));
|
|
return(FALSE);
|
|
}
|
|
|
|
*ppServer = NULL;
|
|
|
|
if (pMessage->MessageId == PCT_MSG_ERROR)
|
|
{
|
|
pError = (PPct_Error)pMessage;
|
|
*ErrorInfo = COMBINEBYTES(pError->ErrorMsb, pError->ErrorLsb);
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Verify Header:
|
|
//
|
|
|
|
if ((pMessage->MessageId != PCT_MSG_SERVER_HELLO) ||
|
|
(pMessage->ServerVersionMsb != MSBOF(PCT_VERSION_1)) ||
|
|
(pMessage->ServerVersionLsb != LSBOF(PCT_VERSION_1)) )
|
|
{
|
|
SetLastError((ULONG) SEC_E_INVALID_TOKEN);
|
|
return(FALSE);
|
|
}
|
|
|
|
cbCertificate = COMBINEBYTES(pMessage->CertificateLenMsb,
|
|
pMessage->CertificateLenLsb);
|
|
|
|
cCertSpecs = COMBINEBYTES(pMessage->CertSpecsLenMsb,
|
|
pMessage->CertSpecsLenLsb);
|
|
|
|
cCertSpecs /= sizeof(ExtCertSpec);
|
|
|
|
|
|
cSigSpecs = COMBINEBYTES(pMessage->ClientSigSpecsLenMsb,
|
|
pMessage->ClientSigSpecsLenLsb);
|
|
|
|
cSigSpecs /= sizeof(ExtSigSpec);
|
|
|
|
cbResponse = COMBINEBYTES(pMessage->ResponseLenMsb,
|
|
pMessage->ResponseLenLsb);
|
|
|
|
if (SingleAlloc)
|
|
{
|
|
pCanonical = LocalAlloc(LMEM_FIXED, sizeof(Server_Hello) +
|
|
cbCertificate +
|
|
cCertSpecs * sizeof(CertSpec) +
|
|
cSigSpecs * sizeof(SigSpec));
|
|
|
|
if (!pCanonical)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Set up pointers to be in this memory allocation.
|
|
//
|
|
|
|
pCanonical->pCertificate = (PUCHAR) (pCanonical + 1);
|
|
pCanonical->pClientCertSpecs = (PCertSpec) (pCanonical->pCertificate +
|
|
cbCertificate);
|
|
pCanonical->pClientSigSpecs = (PSigSpec)(pCanonical->pClientCertSpecs +
|
|
cCertSpecs);
|
|
}
|
|
else
|
|
{
|
|
pCanonical = LocalAlloc(LMEM_FIXED, sizeof(Server_Hello));
|
|
|
|
if (pCanonical)
|
|
{
|
|
pCanonical->pCertificate = LocalAlloc(LMEM_FIXED, cbCertificate);
|
|
pCanonical->pClientCertSpecs = LocalAlloc(LMEM_FIXED,
|
|
cCertSpecs * sizeof(CertSpec) );
|
|
pCanonical->pClientSigSpecs = LocalAlloc(LMEM_FIXED,
|
|
cSigSpecs * sizeof(SigSpec) );
|
|
}
|
|
|
|
if (!pCanonical ||
|
|
!pCanonical->pCertificate ||
|
|
!pCanonical->pClientCertSpecs ||
|
|
!pCanonical->pClientSigSpecs)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Expand out:
|
|
//
|
|
|
|
pCanonical->RestartOk = (DWORD) pMessage->RestartSessionOK;
|
|
pCanonical->ClientAuthReq = (DWORD)pMessage->ClientAuthReq;
|
|
pCanonical->SrvCertSpec = MapCertFromExternal(pMessage->CertSpecData);
|
|
pCanonical->SrvCipherSpec =MapCipherFromExternal(pMessage->CipherSpecData);
|
|
pCanonical->SrvHashSpec = MapHashFromExternal(pMessage->HashSpecData);
|
|
pCanonical->SrvExchSpec = MapExchFromExternal(pMessage->ExchSpecData);
|
|
pCanonical->CertificateLen = cbCertificate;
|
|
pCanonical->ResponseLen = cbResponse;
|
|
|
|
CopyMemory((PUCHAR)pCanonical->Connection.bSessionId,
|
|
pMessage->ConnectionIdData,
|
|
PCT_SESSION_ID_SIZE);
|
|
|
|
pBuffer = pMessage->VariantData;
|
|
|
|
CopyMemory(pCanonical->pCertificate, pBuffer, cbCertificate);
|
|
pBuffer += cbCertificate;
|
|
|
|
for (i = 0 ; i < cCertSpecs ; i++ )
|
|
{
|
|
pCanonical->pClientCertSpecs[i] = MapCertFromExternal(
|
|
*(PExtCertSpec)pBuffer);
|
|
pBuffer += sizeof(CertSpec);
|
|
}
|
|
|
|
for (i = 0 ; i < cSigSpecs ; i++ )
|
|
{
|
|
pCanonical->pClientSigSpecs[i] = MapSigFromExternal(
|
|
*(PExtSigSpec)pBuffer);
|
|
pBuffer += sizeof(SigSpec);
|
|
}
|
|
|
|
CopyMemory(pCanonical->Response, pBuffer, cbResponse);
|
|
|
|
*ppServer = pCanonical;
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
BOOL
|
|
PackClientMasterKey(
|
|
PClient_Master_Key pCanonical,
|
|
PPct_Client_Master_Key *ppNetwork,
|
|
DWORD * pcbNetwork)
|
|
{
|
|
DWORD MessageLength;
|
|
DWORD TotalSpace;
|
|
PPct_Client_Master_Key pMessage;
|
|
PUCHAR pBuffer;
|
|
|
|
MessageLength = pCanonical->ClearKeyLen +
|
|
pCanonical->EncryptedKeyLen +
|
|
pCanonical->KeyArgLen +
|
|
pCanonical->VerifyPreludeLen +
|
|
pCanonical->ClientCertLen +
|
|
pCanonical->ResponseLen +
|
|
sizeof(Pct_Client_Master_Key) -
|
|
(sizeof(Pct_Record_Header) + 1) ;
|
|
|
|
TotalSpace = MessageLength + 2;
|
|
|
|
if ((!pcbNetwork) || (!ppNetwork))
|
|
return (FALSE);
|
|
|
|
if ((*ppNetwork) && (*pcbNetwork < TotalSpace))
|
|
{
|
|
*pcbNetwork = TotalSpace;
|
|
return(FALSE);
|
|
}
|
|
|
|
*pcbNetwork = TotalSpace;
|
|
|
|
if (*ppNetwork)
|
|
{
|
|
pMessage = *ppNetwork;
|
|
}
|
|
else
|
|
{
|
|
pMessage = PctExternalAlloc(TotalSpace);
|
|
if (!pMessage)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
pBuffer = pMessage->VariantData;
|
|
|
|
pMessage->Header.Byte0 = MSBOF(MessageLength) | 0x80;
|
|
pMessage->Header.Byte1 = LSBOF(MessageLength);
|
|
|
|
pMessage->MessageId = PCT_MSG_CLIENT_MASTER_KEY;
|
|
|
|
pMessage->ClearKeyLenMsb = MSBOF(pCanonical->ClearKeyLen);
|
|
pMessage->ClearKeyLenLsb = LSBOF(pCanonical->ClearKeyLen);
|
|
|
|
CopyMemory(pBuffer, pCanonical->ClearKey, pCanonical->ClearKeyLen);
|
|
|
|
pBuffer += pCanonical->ClearKeyLen;
|
|
|
|
pMessage->EncryptedKeyLenMsb = MSBOF(pCanonical->EncryptedKeyLen);
|
|
pMessage->EncryptedKeyLenLsb = LSBOF(pCanonical->EncryptedKeyLen);
|
|
|
|
CopyMemory(pBuffer, pCanonical->EncryptedKey, pCanonical->EncryptedKeyLen);
|
|
pBuffer += pCanonical->EncryptedKeyLen;
|
|
|
|
pMessage->KeyArgLenMsb = MSBOF(pCanonical->KeyArgLen);
|
|
pMessage->KeyArgLenLsb = LSBOF(pCanonical->KeyArgLen);
|
|
|
|
CopyMemory(pBuffer, pCanonical->KeyArg, pCanonical->KeyArgLen);
|
|
|
|
pMessage->VerifyPreludeLenMsb = MSBOF(pCanonical->VerifyPreludeLen);
|
|
pMessage->VerifyPreludeLenLsb = LSBOF(pCanonical->VerifyPreludeLen);
|
|
|
|
CopyMemory(pBuffer, pCanonical->VerifyPrelude,
|
|
pCanonical->VerifyPreludeLen);
|
|
|
|
pMessage->ClientCertLenMsb = MSBOF(pCanonical->ClientCertLen);
|
|
pMessage->ClientCertLenLsb = LSBOF(pCanonical->ClientCertLen);
|
|
|
|
CopyMemory(pBuffer, pCanonical->ClientCert, pCanonical->ClientCertLen);
|
|
|
|
pMessage->ResponseLenMsb = MSBOF(pCanonical->ResponseLen);
|
|
pMessage->ResponseLenLsb = LSBOF(pCanonical->ResponseLen);
|
|
|
|
CopyMemory(pBuffer, pCanonical->Response, pCanonical->ResponseLen);
|
|
|
|
*ppNetwork = pMessage;
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
UnpackClientMasterKey(
|
|
DWORD *ErrorInfo,
|
|
PPct_Client_Master_Key pMessage,
|
|
DWORD cbMessage,
|
|
PClient_Master_Key * ppClient)
|
|
{
|
|
PClient_Master_Key pCanonical;
|
|
PPct_Error pError;
|
|
PUCHAR pBuffer;
|
|
DWORD ReportedSize;
|
|
|
|
ReportedSize = SIZEOF(pMessage);
|
|
if (ReportedSize > cbMessage)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
*ppClient = NULL;
|
|
|
|
if (pMessage->MessageId == PCT_MSG_ERROR)
|
|
{
|
|
pError = (PPct_Error)pMessage;
|
|
*ErrorInfo = COMBINEBYTES(pError->ErrorMsb, pError->ErrorLsb);
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
if ((pMessage->MessageId != PCT_MSG_CLIENT_MASTER_KEY))
|
|
{
|
|
SetLastError((ULONG) SEC_E_INVALID_TOKEN);
|
|
return(FALSE);
|
|
}
|
|
|
|
pCanonical = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof(Client_Master_Key) );
|
|
|
|
if (!pCanonical)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pCanonical->ClearKeyLen = COMBINEBYTES( pMessage->ClearKeyLenMsb,
|
|
pMessage->ClearKeyLenLsb );
|
|
|
|
pCanonical->EncryptedKeyLen = COMBINEBYTES( pMessage->EncryptedKeyLenMsb,
|
|
pMessage->EncryptedKeyLenLsb );
|
|
|
|
pCanonical->KeyArgLen = COMBINEBYTES( pMessage->KeyArgLenMsb,
|
|
pMessage->KeyArgLenLsb );
|
|
|
|
pCanonical->VerifyPreludeLen = COMBINEBYTES( pMessage->VerifyPreludeLenMsb,
|
|
pMessage->VerifyPreludeLenLsb );
|
|
|
|
pCanonical->ClientCertLen = COMBINEBYTES( pMessage->ClientCertLenMsb,
|
|
pMessage->ClientCertLenLsb );
|
|
|
|
pCanonical->ResponseLen = COMBINEBYTES( pMessage->ResponseLenMsb,
|
|
pMessage->ResponseLenLsb );
|
|
|
|
// defensive checks.....
|
|
|
|
if ((pCanonical->ClearKeyLen > MASTER_KEY_SIZE) ||
|
|
(pCanonical->EncryptedKeyLen > ENCRYPTED_KEY_SIZE) ||
|
|
(pCanonical->KeyArgLen) ||
|
|
(pCanonical->VerifyPreludeLen > RESPONSE_SIZE) ||
|
|
(pCanonical->ClientCertLen > CERT_SIZE) ||
|
|
(pCanonical->ResponseLen > RESPONSE_SIZE))
|
|
{
|
|
LocalFree(pCanonical);
|
|
pCanonical = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
// note: funny little +1 below is to compensate for the
|
|
// variantdata[1] element of Pct_Client_Master_Key
|
|
|
|
if ((pCanonical->ClearKeyLen +
|
|
pCanonical->EncryptedKeyLen +
|
|
pCanonical->KeyArgLen +
|
|
pCanonical->VerifyPreludeLen +
|
|
pCanonical->ClientCertLen +
|
|
pCanonical->ResponseLen) !=
|
|
(cbMessage + 1 - sizeof(Pct_Client_Master_Key)))
|
|
{
|
|
LocalFree(pCanonical);
|
|
pCanonical = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
// ok, we're pretty sure we aren't going to fault.
|
|
|
|
pBuffer = pMessage->VariantData;
|
|
|
|
CopyMemory(pCanonical->ClearKey, pBuffer, pCanonical->ClearKeyLen );
|
|
|
|
pBuffer += pCanonical->ClearKeyLen;
|
|
|
|
CopyMemory(pCanonical->EncryptedKey, pBuffer, pCanonical->EncryptedKeyLen);
|
|
|
|
pBuffer += pCanonical->EncryptedKeyLen;
|
|
|
|
CopyMemory( pCanonical->KeyArg, pBuffer, pCanonical->KeyArgLen );
|
|
|
|
pBuffer += pCanonical->KeyArgLen;
|
|
|
|
CopyMemory( pCanonical->VerifyPrelude, pBuffer,
|
|
pCanonical->VerifyPreludeLen );
|
|
|
|
pBuffer += pCanonical->VerifyPreludeLen;
|
|
|
|
CopyMemory( pCanonical->ClientCert, pBuffer, pCanonical->ClientCertLen );
|
|
|
|
pBuffer += pCanonical->ClientCertLen;
|
|
|
|
CopyMemory( pCanonical->Response, pBuffer, pCanonical->ResponseLen );
|
|
|
|
*ppClient = pCanonical;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOL
|
|
PackServerVerify(
|
|
PServer_Verify pCanonical,
|
|
PPct_Server_Verify * ppNetwork,
|
|
DWORD * pcbNetwork)
|
|
{
|
|
DWORD TotalSpace;
|
|
DWORD MessageLength;
|
|
PPct_Server_Verify pMessage;
|
|
DWORD Size;
|
|
PUCHAR pBuffer;
|
|
DWORD i;
|
|
|
|
MessageLength = pCanonical->ResponseLen +
|
|
sizeof(Pct_Server_Verify) -
|
|
(sizeof(Pct_Record_Header) + 1 );
|
|
|
|
TotalSpace = MessageLength + 2;
|
|
|
|
if ((!pcbNetwork) || (!ppNetwork))
|
|
return (FALSE);
|
|
|
|
if ((*ppNetwork) && (*pcbNetwork < TotalSpace))
|
|
{
|
|
*pcbNetwork = TotalSpace;
|
|
return(FALSE);
|
|
}
|
|
|
|
*pcbNetwork = TotalSpace;
|
|
|
|
if (*ppNetwork)
|
|
{
|
|
pMessage = *ppNetwork;
|
|
}
|
|
else
|
|
{
|
|
pMessage = PctExternalAlloc( TotalSpace );
|
|
if (!pMessage)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
pMessage->MessageId = PCT_MSG_SERVER_VERIFY;
|
|
|
|
pMessage->Header.Byte0 = MSBOF(MessageLength) | 0x80;
|
|
pMessage->Header.Byte1 = LSBOF(MessageLength);
|
|
|
|
CopyMemory(pMessage->SessionIdData, pCanonical->SessionIdData,
|
|
PCT_SESSION_ID_SIZE);
|
|
|
|
pBuffer = pMessage->VariantData;
|
|
|
|
//
|
|
// Pack certificate if present
|
|
//
|
|
|
|
pMessage->ResponseLenMsb = MSBOF(pCanonical->ResponseLen);
|
|
pMessage->ResponseLenLsb = LSBOF(pCanonical->ResponseLen);
|
|
|
|
if (pCanonical->ResponseLen)
|
|
{
|
|
CopyMemory( pBuffer,
|
|
pCanonical->Response,
|
|
pCanonical->ResponseLen);
|
|
}
|
|
|
|
*ppNetwork = pMessage;
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
UnpackServerVerify(
|
|
BOOL SingleAlloc,
|
|
DWORD *ErrorInfo,
|
|
PPct_Server_Verify pMessage,
|
|
DWORD cbMessage,
|
|
PServer_Verify * ppServer)
|
|
{
|
|
PServer_Verify pCanonical;
|
|
PPct_Error pError;
|
|
PUCHAR pBuffer;
|
|
DWORD cbResponse;
|
|
DWORD i;
|
|
DWORD ReportedSize;
|
|
|
|
ReportedSize = SIZEOF(pMessage);
|
|
if (ReportedSize > cbMessage)
|
|
{
|
|
DebugLog((DEB_WARN, "ReportedSize (%d, %#x) > actual size (%d, %#x)\n",
|
|
ReportedSize, ReportedSize, cbMessage, cbMessage));
|
|
return(FALSE);
|
|
}
|
|
|
|
*ppServer = NULL;
|
|
|
|
if (pMessage->MessageId == PCT_MSG_ERROR)
|
|
{
|
|
pError = (PPct_Error)pMessage;
|
|
*ErrorInfo = COMBINEBYTES(pError->ErrorMsb, pError->ErrorLsb);
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Verify Header:
|
|
//
|
|
|
|
if (pMessage->MessageId != PCT_MSG_SERVER_VERIFY)
|
|
{
|
|
SetLastError((ULONG) SEC_E_INVALID_TOKEN);
|
|
return(FALSE);
|
|
}
|
|
|
|
cbResponse = COMBINEBYTES(pMessage->ResponseLenMsb,
|
|
pMessage->ResponseLenLsb);
|
|
|
|
if (cbResponse > PCT_SESSION_ID_SIZE)
|
|
return FALSE;
|
|
|
|
pCanonical = LocalAlloc(LMEM_FIXED, sizeof(Server_Verify));
|
|
|
|
if (!pCanonical)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Expand out:
|
|
//
|
|
|
|
pCanonical->ResponseLen = cbResponse;
|
|
|
|
CopyMemory((PUCHAR)pCanonical->SessionIdData, pMessage->SessionIdData,
|
|
PCT_SESSION_ID_SIZE);
|
|
|
|
pBuffer = pMessage->VariantData;
|
|
|
|
CopyMemory(pCanonical->Response, pBuffer, cbResponse);
|
|
|
|
*ppServer = pCanonical;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL
|
|
PackPctError(
|
|
PPctError pCanonical,
|
|
PPct_Error * ppNetwork,
|
|
DWORD * pcbNetwork)
|
|
{
|
|
DWORD TotalSpace;
|
|
DWORD MessageLength;
|
|
PPct_Error pMessage;
|
|
DWORD Size;
|
|
PUCHAR pBuffer;
|
|
DWORD i;
|
|
|
|
MessageLength = pCanonical->ErrInfoLen +
|
|
sizeof(Pct_Error) - sizeof(Pct_Record_Header) - 1;
|
|
|
|
TotalSpace = MessageLength + 2;
|
|
|
|
if ((!pcbNetwork) || (!ppNetwork))
|
|
return (FALSE);
|
|
|
|
if ((*ppNetwork) && (*pcbNetwork < TotalSpace))
|
|
{
|
|
*pcbNetwork = TotalSpace;
|
|
return(FALSE);
|
|
}
|
|
|
|
*pcbNetwork = TotalSpace;
|
|
|
|
if (*ppNetwork)
|
|
{
|
|
pMessage = *ppNetwork;
|
|
}
|
|
else
|
|
{
|
|
pMessage = PctExternalAlloc( TotalSpace );
|
|
if (!pMessage)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
*pcbNetwork = TotalSpace;
|
|
}
|
|
|
|
pMessage->Header.Byte0 = MSBOF(MessageLength) | 0x80;
|
|
pMessage->Header.Byte1 = LSBOF(MessageLength);
|
|
|
|
pMessage->MessageId = PCT_MSG_ERROR;
|
|
|
|
pMessage->ErrorMsb = MSBOF(pCanonical->Error);
|
|
pMessage->ErrorLsb = LSBOF(pCanonical->Error);
|
|
|
|
pMessage->ErrorInfoMsb = MSBOF(pCanonical->ErrInfoLen);
|
|
pMessage->ErrorInfoLsb = LSBOF(pCanonical->ErrInfoLen);
|
|
|
|
memcpy(pMessage->VariantData, pCanonical->ErrInfo, pCanonical->ErrInfoLen);
|
|
|
|
*ppNetwork = pMessage;
|
|
|
|
return( TRUE );
|
|
}
|