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

1288 lines
35 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: pct1pckl.c
//
// Contents:
//
// Classes:
//
// Functions:
//
// History:
//
//----------------------------------------------------------------------------
#include <spbase.h>
#include <pct1msg.h>
#include <pct1prot.h>
#define PCT_OFFSET_OF(t, v) ((DWORD)(ULONG_PTR)&(((t)NULL)->v))
#define SIZEOF(pMessage) (Pct1RecordSize((PPCT1_MESSAGE_HEADER) pMessage ) )
DWORD MapCipherToExternal(CipherSpec Internal, ExtCipherSpec UNALIGNED *External)
{
*External = htonl(Internal);
return TRUE;
}
DWORD MapHashToExternal(HashSpec Internal, ExtHashSpec UNALIGNED *External)
{
*External = htons((ExtHashSpec)Internal);
return TRUE;
}
DWORD MapCertToExternal(CertSpec Internal, ExtCertSpec UNALIGNED *External)
{
*External = htons((ExtCertSpec)Internal);
return TRUE;
}
DWORD MapExchToExternal(ExchSpec Internal, ExtExchSpec UNALIGNED *External)
{
*External = htons((ExtExchSpec)Internal);
return TRUE;
}
DWORD MapSigToExternal(SigSpec Internal, ExtSigSpec UNALIGNED *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
Pct1RecordSize(
PPCT1_MESSAGE_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);
}
SP_STATUS
Pct1PackClientHello(
PPct1_Client_Hello pCanonical,
PSPBuffer pCommOutput)
{
DWORD cbMessage;
PPCT1_CLIENT_HELLO pMessage;
DWORD Size;
PUCHAR pBuffer;
DWORD i, iBuff;
SP_BEGIN("Pct1PackClientHello");
if(pCanonical == NULL || pCommOutput == NULL)
{
SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
}
pCommOutput->cbData = 0;
if(pCanonical->cbSessionID != PCT_SESSION_ID_SIZE ||
pCanonical->cbChallenge != PCT_CHALLENGE_SIZE)
{
SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
}
pCommOutput->cbData = PCT_OFFSET_OF(PPCT1_CLIENT_HELLO, VariantData) +
pCanonical->cCipherSpecs * sizeof(ExtCipherSpec) +
pCanonical->cHashSpecs * sizeof(ExtHashSpec) +
pCanonical->cCertSpecs * sizeof(ExtCertSpec) +
pCanonical->cExchSpecs * sizeof(ExtExchSpec) +
pCanonical->cbKeyArgSize;
cbMessage = pCommOutput->cbData - sizeof(PCT1_MESSAGE_HEADER);
if (cbMessage > PCT_MAX_SHAKE_LEN)
{
SP_RETURN(SP_LOG_RESULT(PCT_INT_DATA_OVERFLOW));
}
/* are we allocating our own memory? */
if(pCommOutput->pvBuffer == NULL)
{
pCommOutput->pvBuffer = SPExternalAlloc(pCommOutput->cbData);
if (NULL == pCommOutput->pvBuffer)
{
SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
}
pCommOutput->cbBuffer = pCommOutput->cbData;
}
if(pCommOutput->cbData > pCommOutput->cbBuffer)
{
// Required size returned in pCommOutput->cbData.
SP_RETURN(PCT_INT_BUFF_TOO_SMALL);
}
pMessage = pCommOutput->pvBuffer;
pMessage->MessageId = PCT1_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);
pMessage->KeyArgLenMsb = MSBOF(pCanonical->cbKeyArgSize);
pMessage->KeyArgLenLsb = LSBOF(pCanonical->cbKeyArgSize);
CopyMemory( pMessage->SessionIdData,
pCanonical->SessionID,
pCanonical->cbSessionID);
CopyMemory( pMessage->ChallengeData,
pCanonical->Challenge,
pCanonical->cbChallenge);
pBuffer = pMessage->VariantData;
iBuff = 0;
for (i = 0; i < pCanonical->cCipherSpecs ; i++ )
{
if (MapCipherToExternal(pCanonical->pCipherSpecs[i],
&((ExtCipherSpec UNALIGNED *) pBuffer)[iBuff]) )
{
iBuff++;
}
}
Size = iBuff*sizeof(ExtCipherSpec);
pMessage->CipherSpecsLenMsb = MSBOF(Size);
pMessage->CipherSpecsLenLsb = LSBOF(Size);
pBuffer += Size;
cbMessage -= (pCanonical->cCipherSpecs - iBuff)*sizeof(ExtCipherSpec);
iBuff = 0;
for (i = 0; i < pCanonical->cHashSpecs ; i++ )
{
if (MapHashToExternal(pCanonical->pHashSpecs[i],
&((ExtHashSpec UNALIGNED *) pBuffer)[iBuff]) )
{
iBuff++;
}
}
Size = iBuff*sizeof(ExtHashSpec);
pBuffer += Size;
pMessage->HashSpecsLenMsb = MSBOF(Size);
pMessage->HashSpecsLenLsb = LSBOF(Size);
cbMessage -= (pCanonical->cHashSpecs - iBuff)*sizeof(ExtHashSpec);
iBuff = 0;
for (i = 0; i < pCanonical->cCertSpecs ; i++ )
{
if (MapCertToExternal(pCanonical->pCertSpecs[i],
&((ExtCertSpec UNALIGNED *) pBuffer)[iBuff]))
{
iBuff ++;
}
}
Size = iBuff*sizeof(ExtCertSpec);
pBuffer += Size;
pMessage->CertSpecsLenMsb = MSBOF(Size);
pMessage->CertSpecsLenLsb = LSBOF(Size);
cbMessage -= (pCanonical->cCertSpecs - iBuff)*sizeof(ExtCertSpec);
iBuff = 0;
for (i = 0; i < pCanonical->cExchSpecs ; i++ )
{
if (MapExchToExternal(pCanonical->pExchSpecs[i],
&((ExtExchSpec UNALIGNED *) pBuffer)[iBuff]) )
{
iBuff++;
}
}
Size = iBuff*sizeof(ExtExchSpec);
pBuffer += Size;
pMessage->ExchSpecsLenMsb = MSBOF(Size);
pMessage->ExchSpecsLenLsb = LSBOF(Size);
cbMessage -= (pCanonical->cExchSpecs - iBuff)*sizeof(ExtExchSpec);
if(pCanonical->pKeyArg)
{
CopyMemory(pBuffer, pCanonical->pKeyArg, pCanonical->cbKeyArgSize);
pBuffer += pCanonical->cbKeyArgSize;
}
pCommOutput->cbData = cbMessage + 2;
pMessage->Header.Byte0 = MSBOF(cbMessage) | 0x80;
pMessage->Header.Byte1 = LSBOF(cbMessage);
SP_RETURN(PCT_ERR_OK);
}
SP_STATUS
Pct1UnpackClientHello(
PSPBuffer pInput,
PPct1_Client_Hello * ppClient)
{
PPCT1_CLIENT_HELLO pMessage;
DWORD ReportedSize;
DWORD CipherSpecsSize, HashSpecsSize, CertSpecsSize;
DWORD ExchSpecsSize;
DWORD cCipherSpecs, cHashSpecs, cCertSpecs, cExchSpecs;
DWORD cOffsetBytes, KeyArgSize;
PPct1_Client_Hello pCanonical;
PUCHAR pBuffer;
DWORD i;
SP_BEGIN("Pct1UnpackClientHello");
if(pInput == NULL ||
ppClient == NULL ||
pInput->pvBuffer == NULL)
{
SP_RETURN(PCT_INT_INTERNAL_ERROR);
}
pMessage = pInput->pvBuffer;
if(pInput->cbData < 2)
{
pInput->cbData = 2;
SP_RETURN(PCT_INT_INCOMPLETE_MSG);
}
ReportedSize = SIZEOF(pMessage);
if ((ReportedSize+2) > pInput->cbData)
{
pInput->cbData = ReportedSize+2;
SP_RETURN(PCT_INT_INCOMPLETE_MSG);
}
if(ReportedSize < PCT_OFFSET_OF(PPCT1_CLIENT_HELLO, VariantData))
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
if(ReportedSize > PCT_MAX_SHAKE_LEN)
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
if ((pMessage->VersionMsb & 0x80) == 0)
{
SP_RETURN (PCT_ERR_SSL_STYLE_MSG);
}
/* We don't recognize hello messages of less version than ourselves,
* those will be handled by a previous version of the code */
if ((pMessage->MessageId != PCT1_MSG_CLIENT_HELLO) ||
((pMessage->VersionMsb << 8 | pMessage->VersionLsb) < PCT_VERSION_1))
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
cOffsetBytes = COMBINEBYTES( pMessage->OffsetMsb,
pMessage->OffsetLsb );
if(cOffsetBytes < PCT_CH_OFFSET_V1)
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
*ppClient = NULL;
CipherSpecsSize = COMBINEBYTES( pMessage->CipherSpecsLenMsb,
pMessage->CipherSpecsLenLsb );
HashSpecsSize = COMBINEBYTES( pMessage->HashSpecsLenMsb,
pMessage->HashSpecsLenLsb );
CertSpecsSize = COMBINEBYTES( pMessage->CertSpecsLenMsb,
pMessage->CertSpecsLenLsb );
ExchSpecsSize = COMBINEBYTES( pMessage->ExchSpecsLenMsb,
pMessage->ExchSpecsLenLsb );
KeyArgSize = COMBINEBYTES( pMessage->KeyArgLenMsb,
pMessage->KeyArgLenLsb );
/* check that this all fits into the message */
if (PCT_OFFSET_OF(PPCT1_CLIENT_HELLO, VariantData)
- sizeof(PCT1_MESSAGE_HEADER) /* don't count the header */
+ cOffsetBytes - PCT_CH_OFFSET_V1
+ CipherSpecsSize
+ HashSpecsSize
+ CertSpecsSize
+ ExchSpecsSize
+ KeyArgSize != ReportedSize)
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
cCipherSpecs = CipherSpecsSize / sizeof(ExtCipherSpec);
cHashSpecs = HashSpecsSize / sizeof(ExtHashSpec);
cExchSpecs = ExchSpecsSize / sizeof(ExtExchSpec);
cCertSpecs = CertSpecsSize / sizeof(ExtCertSpec);
if(KeyArgSize > SP_MAX_KEY_ARGS)
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
/* Allocate a buffer for the canonical client hello */
pCanonical = (PPct1_Client_Hello)SPExternalAlloc(
sizeof(Pct1_Client_Hello) +
cCipherSpecs * sizeof(CipherSpec) +
cHashSpecs * sizeof(HashSpec) +
cCertSpecs * sizeof(CertSpec) +
cExchSpecs * sizeof(ExchSpec) +
KeyArgSize);
if (!pCanonical)
{
SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
}
pCanonical->cbKeyArgSize = KeyArgSize;
pCanonical->pCipherSpecs = (PCipherSpec) (pCanonical + 1);
pCanonical->pHashSpecs = (PHashSpec) (pCanonical->pCipherSpecs +
cCipherSpecs);
pCanonical->pCertSpecs = (PCertSpec) (pCanonical->pHashSpecs +
cHashSpecs);
pCanonical->pExchSpecs = (PExchSpec) (pCanonical->pCertSpecs +
cCertSpecs);
pCanonical->pKeyArg = (PUCHAR)(pCanonical->pExchSpecs + cExchSpecs);
CopyMemory( pCanonical->SessionID,
pMessage->SessionIdData,
PCT_SESSION_ID_SIZE);
pCanonical->cbSessionID = PCT_SESSION_ID_SIZE;
CopyMemory( pCanonical->Challenge,
pMessage->ChallengeData,
PCT_CHALLENGE_SIZE );
pCanonical->cbChallenge = PCT_CHALLENGE_SIZE;
pBuffer = &pMessage->OffsetLsb + 1 + cOffsetBytes;
pCanonical->cCipherSpecs = cCipherSpecs;
for (i = 0 ; i < cCipherSpecs ; i++ )
{
pCanonical->pCipherSpecs[i] = MapCipherFromExternal(*(ExtCipherSpec UNALIGNED *)
pBuffer);
pBuffer += sizeof(ExtCipherSpec);
}
pCanonical->cHashSpecs = cHashSpecs;
for (i = 0 ; i < cHashSpecs ; i++ )
{
pCanonical->pHashSpecs[i] = MapHashFromExternal(*(ExtHashSpec UNALIGNED *)
pBuffer);
pBuffer += sizeof(ExtHashSpec);
}
pCanonical->cCertSpecs = cCertSpecs;
for (i = 0 ; i < cCertSpecs ; i++ )
{
pCanonical->pCertSpecs[i] = MapCertFromExternal(*(ExtCertSpec UNALIGNED *)
pBuffer);
pBuffer += sizeof(ExtCertSpec);
}
pCanonical->cExchSpecs = cExchSpecs;
for (i = 0 ; i < cExchSpecs ; i++ )
{
pCanonical->pExchSpecs[i] = MapExchFromExternal(*(ExtExchSpec UNALIGNED *)
pBuffer);
pBuffer += sizeof(ExtExchSpec);
}
CopyMemory(pCanonical->pKeyArg, pBuffer, KeyArgSize);
*ppClient = pCanonical;
pInput->cbData = ReportedSize + sizeof(PCT1_MESSAGE_HEADER);
SP_RETURN(PCT_ERR_OK);
}
SP_STATUS
Pct1PackServerHello(
PPct1_Server_Hello pCanonical,
PSPBuffer pCommOutput)
{
DWORD cbMessage;
PPCT1_SERVER_HELLO pMessage;
DWORD Size;
PUCHAR pBuffer;
DWORD i, iBuff;
SP_BEGIN("Pct1PackServerHello");
if(pCanonical == NULL || pCommOutput == NULL)
{
SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
}
pCommOutput->cbData = 0;
if(pCanonical->cbConnectionID != PCT_SESSION_ID_SIZE)
{
SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
}
cbMessage = pCanonical->CertificateLen +
pCanonical->cCertSpecs * sizeof(ExtCertSpec) +
pCanonical->cSigSpecs * sizeof(ExtSigSpec) +
pCanonical->ResponseLen +
PCT_OFFSET_OF(PPCT1_SERVER_HELLO, VariantData) -
sizeof(PCT1_MESSAGE_HEADER);
if (cbMessage > PCT_MAX_SHAKE_LEN)
{
SP_RETURN(SP_LOG_RESULT(PCT_INT_DATA_OVERFLOW));
}
pCommOutput->cbData = cbMessage + 2;
/* are we allocating our own memory? */
if(pCommOutput->pvBuffer == NULL)
{
pCommOutput->pvBuffer = SPExternalAlloc(pCommOutput->cbData);
if (NULL == pCommOutput->pvBuffer)
{
SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
}
pCommOutput->cbBuffer = pCommOutput->cbData;
}
if(pCommOutput->cbData > pCommOutput->cbBuffer)
{
// Required size returned in pCommOutput->cbData.
SP_RETURN(PCT_INT_BUFF_TOO_SMALL);
}
pMessage = pCommOutput->pvBuffer;
pMessage->MessageId = PCT1_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->ConnectionID,
pCanonical->cbConnectionID);
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 ;
}
iBuff = 0;
for (i = 0; i < pCanonical->cCertSpecs ; i++ )
{
if (MapCertToExternal(pCanonical->pClientCertSpecs[i],
&((ExtCertSpec UNALIGNED *) pBuffer)[iBuff]))
{
iBuff ++;
}
}
Size = iBuff*sizeof(ExtCertSpec);
pBuffer += Size;
pMessage->CertSpecsLenMsb = MSBOF(Size);
pMessage->CertSpecsLenLsb = LSBOF(Size);
cbMessage -= (pCanonical->cCertSpecs - iBuff)*sizeof(ExtCertSpec);
iBuff = 0;
for (i = 0; i < pCanonical->cSigSpecs ; i++ )
{
if (MapSigToExternal(pCanonical->pClientSigSpecs[i],
&((ExtSigSpec UNALIGNED *) pBuffer)[iBuff]) )
{
iBuff++;
}
}
Size = iBuff*sizeof(ExtSigSpec);
pBuffer += Size;
pMessage->ClientSigSpecsLenMsb = MSBOF(Size);
pMessage->ClientSigSpecsLenLsb = LSBOF(Size);
cbMessage -= (pCanonical->cSigSpecs - iBuff)*sizeof(ExtSigSpec);
pMessage->ResponseLenMsb = MSBOF(pCanonical->ResponseLen);
pMessage->ResponseLenLsb = LSBOF(pCanonical->ResponseLen);
CopyMemory( pBuffer,
pCanonical->Response,
pCanonical->ResponseLen);
pBuffer += pCanonical->ResponseLen;
pCommOutput->cbData = cbMessage + 2;
pMessage->Header.Byte0 = MSBOF(cbMessage) | 0x80;
pMessage->Header.Byte1 = LSBOF(cbMessage);
SP_RETURN(PCT_ERR_OK);
}
SP_STATUS
Pct1UnpackServerHello(
PSPBuffer pInput,
PPct1_Server_Hello * ppServer)
{
PPct1_Server_Hello pCanonical;
PPCT1_SERVER_HELLO pMessage;
PUCHAR pBuffer;
DWORD cbCertificate, cbResponse;
DWORD cCertSpecs, cSigSpecs;
DWORD i;
DWORD ReportedSize;
SP_BEGIN("Pct1UnpackServerHello");
if(pInput == NULL ||
ppServer == NULL ||
pInput->pvBuffer == NULL)
{
SP_RETURN(PCT_INT_INTERNAL_ERROR);
}
pMessage = pInput->pvBuffer;
if(pInput->cbData < 2)
{
pInput->cbData = 2;
SP_RETURN(PCT_INT_INCOMPLETE_MSG);
}
ReportedSize = SIZEOF(pMessage);
if(ReportedSize > PCT_MAX_SHAKE_LEN)
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
if ((ReportedSize+2) > pInput->cbData)
{
pInput->cbData = ReportedSize+2;
SP_RETURN(PCT_INT_INCOMPLETE_MSG);
}
if(ReportedSize < PCT_OFFSET_OF(PPCT1_SERVER_HELLO, VariantData) )
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
/* Verify Header: */
/* we don't handle server hello messages of latter version than ourselves,
* those will be handled by latter verisions of the protocol */
if ((pMessage->MessageId != PCT1_MSG_SERVER_HELLO) ||
((pMessage->ServerVersionMsb << 8 | pMessage->ServerVersionLsb) != PCT_VERSION_1))
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
*ppServer = NULL;
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(cbResponse > PCT1_RESPONSE_SIZE)
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
/* check that this all fits into the message */
if (PCT_OFFSET_OF(PPCT1_SERVER_HELLO, VariantData)
- sizeof(PCT1_MESSAGE_HEADER) /* don't count the header */
+ cbCertificate
+ cCertSpecs*sizeof(ExtCertSpec)
+ cSigSpecs*sizeof(ExtSigSpec)
+ cbResponse != ReportedSize)
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
pCanonical = (PPct1_Server_Hello)SPExternalAlloc(
sizeof(Pct1_Server_Hello) +
cCertSpecs * sizeof(CertSpec) +
cSigSpecs * sizeof(SigSpec) +
cbCertificate);
if (!pCanonical)
{
SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
}
/* Set up pointers to be in this memory allocation. */
pCanonical->pClientCertSpecs = (PCertSpec) (pCanonical + 1);
pCanonical->pClientSigSpecs = (PSigSpec)(pCanonical->pClientCertSpecs +
cCertSpecs);
pCanonical->pCertificate = (PUCHAR) (pCanonical->pClientSigSpecs +
cSigSpecs);
/* 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;
pCanonical->cCertSpecs = cCertSpecs;
pCanonical->cSigSpecs = cSigSpecs;
CopyMemory(pCanonical->ConnectionID,
pMessage->ConnectionIdData,
PCT_SESSION_ID_SIZE);
pCanonical->cbConnectionID= PCT_SESSION_ID_SIZE;
pBuffer = pMessage->VariantData;
CopyMemory(pCanonical->pCertificate, pBuffer, cbCertificate);
pBuffer += cbCertificate;
for (i = 0 ; i < cCertSpecs ; i++ )
{
pCanonical->pClientCertSpecs[i] = MapCertFromExternal(
*(ExtCertSpec UNALIGNED *)pBuffer);
pBuffer += sizeof(ExtCertSpec);
}
for (i = 0 ; i < cSigSpecs ; i++ )
{
pCanonical->pClientSigSpecs[i] = MapSigFromExternal(
*(ExtSigSpec UNALIGNED *)pBuffer);
pBuffer += sizeof(ExtSigSpec);
}
CopyMemory(pCanonical->Response, pBuffer, cbResponse);
*ppServer = pCanonical;
pInput->cbData = ReportedSize + sizeof(PCT1_MESSAGE_HEADER);
SP_RETURN(PCT_ERR_OK);
}
SP_STATUS
Pct1PackClientMasterKey(
PPct1_Client_Master_Key pCanonical,
PSPBuffer pCommOutput)
{
DWORD cbMessage;
PPCT1_CLIENT_MASTER_KEY pMessage;
PUCHAR pBuffer;
SP_BEGIN("Pct1PackClientMasterKey");
if(pCanonical == NULL || pCommOutput == NULL)
{
SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
}
pCommOutput->cbData = 0;
cbMessage = pCanonical->ClearKeyLen +
pCanonical->EncryptedKeyLen +
pCanonical->KeyArgLen +
pCanonical->VerifyPreludeLen +
pCanonical->ClientCertLen +
pCanonical->ResponseLen +
PCT_OFFSET_OF(PPCT1_CLIENT_MASTER_KEY, VariantData) -
sizeof(PCT1_MESSAGE_HEADER);
if (cbMessage > PCT_MAX_SHAKE_LEN)
{
SP_RETURN(SP_LOG_RESULT(PCT_INT_DATA_OVERFLOW));
}
pCommOutput->cbData = cbMessage + 2;
/* are we allocating our own memory? */
if(pCommOutput->pvBuffer == NULL)
{
pCommOutput->pvBuffer = SPExternalAlloc(pCommOutput->cbData);
if (NULL == pCommOutput->pvBuffer)
{
SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
}
pCommOutput->cbBuffer = pCommOutput->cbData;
}
if(pCommOutput->cbData > pCommOutput->cbBuffer)
{
// Required size returned in pCommOutput->cbData.
SP_RETURN(PCT_INT_BUFF_TOO_SMALL);
}
pMessage = pCommOutput->pvBuffer;
pBuffer = pMessage->VariantData;
pMessage->Header.Byte0 = MSBOF(cbMessage) | 0x80;
pMessage->Header.Byte1 = LSBOF(cbMessage);
pMessage->MessageId = PCT1_MSG_CLIENT_MASTER_KEY;
pMessage->ClearKeyLenMsb = MSBOF(pCanonical->ClearKeyLen);
pMessage->ClearKeyLenLsb = LSBOF(pCanonical->ClearKeyLen);
MapSigToExternal(pCanonical->ClientSigSpec, &pMessage->ClientSigSpecData);
MapCertToExternal(pCanonical->ClientCertSpec, &pMessage->ClientCertSpecData);
CopyMemory(pBuffer, pCanonical->ClearKey, pCanonical->ClearKeyLen);
pBuffer += pCanonical->ClearKeyLen;
pMessage->EncryptedKeyLenMsb = MSBOF(pCanonical->EncryptedKeyLen);
pMessage->EncryptedKeyLenLsb = LSBOF(pCanonical->EncryptedKeyLen);
CopyMemory(pBuffer, pCanonical->pbEncryptedKey, pCanonical->EncryptedKeyLen);
pBuffer += pCanonical->EncryptedKeyLen;
pMessage->KeyArgLenMsb = MSBOF(pCanonical->KeyArgLen);
pMessage->KeyArgLenLsb = LSBOF(pCanonical->KeyArgLen);
CopyMemory(pBuffer, pCanonical->KeyArg, pCanonical->KeyArgLen);
pBuffer += pCanonical->KeyArgLen;
pMessage->VerifyPreludeLenMsb = MSBOF(pCanonical->VerifyPreludeLen);
pMessage->VerifyPreludeLenLsb = LSBOF(pCanonical->VerifyPreludeLen);
CopyMemory(pBuffer, pCanonical->VerifyPrelude,
pCanonical->VerifyPreludeLen);
pBuffer += pCanonical->VerifyPreludeLen;
pMessage->ClientCertLenMsb = MSBOF(pCanonical->ClientCertLen);
pMessage->ClientCertLenLsb = LSBOF(pCanonical->ClientCertLen);
CopyMemory(pBuffer, pCanonical->pClientCert, pCanonical->ClientCertLen);
pBuffer += pCanonical->ClientCertLen;
pMessage->ResponseLenMsb = MSBOF(pCanonical->ResponseLen);
pMessage->ResponseLenLsb = LSBOF(pCanonical->ResponseLen);
CopyMemory(pBuffer, pCanonical->pbResponse, pCanonical->ResponseLen);
SP_RETURN(PCT_ERR_OK);
}
SP_STATUS
Pct1UnpackClientMasterKey(
PSPBuffer pInput,
PPct1_Client_Master_Key * ppClient)
{
PPct1_Client_Master_Key pCanonical;
PUCHAR pBuffer;
DWORD ReportedSize;
PPCT1_CLIENT_MASTER_KEY pMessage;
DWORD cbClearKey, cbEncryptedKey, cbKeyArg, cbVerifyPrelude, cbClientCert, cbResponse;
SP_BEGIN("Pct1UnpackClientMasterKey");
if(pInput == NULL ||
ppClient == NULL ||
pInput->pvBuffer == NULL)
{
SP_RETURN(PCT_INT_INTERNAL_ERROR);
}
pMessage = pInput->pvBuffer;
if(pInput->cbData < 2)
{
pInput->cbData = 2;
SP_RETURN(PCT_INT_INCOMPLETE_MSG);
}
ReportedSize = SIZEOF(pMessage);
if(ReportedSize > PCT_MAX_SHAKE_LEN)
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
if ((ReportedSize+2) > pInput->cbData)
{
pInput->cbData = ReportedSize+2;
SP_RETURN(PCT_INT_INCOMPLETE_MSG);
}
if(ReportedSize < PCT_OFFSET_OF(PPCT1_CLIENT_MASTER_KEY, VariantData))
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
/* Verify Header: */
if (pMessage->MessageId != PCT1_MSG_CLIENT_MASTER_KEY )
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
cbClearKey = COMBINEBYTES( pMessage->ClearKeyLenMsb,
pMessage->ClearKeyLenLsb );
cbEncryptedKey = COMBINEBYTES( pMessage->EncryptedKeyLenMsb,
pMessage->EncryptedKeyLenLsb );
cbKeyArg = COMBINEBYTES( pMessage->KeyArgLenMsb,
pMessage->KeyArgLenLsb );
cbVerifyPrelude = COMBINEBYTES( pMessage->VerifyPreludeLenMsb,
pMessage->VerifyPreludeLenLsb );
cbClientCert = COMBINEBYTES( pMessage->ClientCertLenMsb,
pMessage->ClientCertLenLsb );
cbResponse = COMBINEBYTES( pMessage->ResponseLenMsb,
pMessage->ResponseLenLsb );
/* defensive checks..... */
if ((cbClearKey > SP_MAX_MASTER_KEY) ||
(cbKeyArg > PCT1_MAX_KEY_ARGS) ||
(cbVerifyPrelude > RESPONSE_SIZE))
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
if ((PCT_OFFSET_OF(PPCT1_CLIENT_MASTER_KEY, VariantData) -
sizeof(PCT1_MESSAGE_HEADER) +
cbClearKey +
cbEncryptedKey +
cbKeyArg +
cbVerifyPrelude +
cbClientCert +
cbResponse) !=
ReportedSize)
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
*ppClient = NULL;
pCanonical = (PPct1_Client_Master_Key)SPExternalAlloc(
sizeof(Pct1_Client_Master_Key) +
cbClientCert +
cbEncryptedKey +
cbResponse);
if (!pCanonical)
{
SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
}
pCanonical->ClearKeyLen = cbClearKey;
pCanonical->EncryptedKeyLen = cbEncryptedKey;
pCanonical->KeyArgLen = cbKeyArg;
pCanonical->VerifyPreludeLen = cbVerifyPrelude;
pCanonical->ClientCertLen = cbClientCert;
pCanonical->ResponseLen = cbResponse;
/* defensive checks..... */
pCanonical->ClientCertSpec = MapCertFromExternal(pMessage->ClientCertSpecData);
pCanonical->pClientCert = (PUCHAR)(pCanonical+1);
pCanonical->ClientSigSpec = MapSigFromExternal(pMessage->ClientSigSpecData);
/* ok, we're pretty sure we aren't going to fault. */
pBuffer = pMessage->VariantData;
CopyMemory(pCanonical->ClearKey, pBuffer, pCanonical->ClearKeyLen );
pBuffer += pCanonical->ClearKeyLen;
pCanonical->pbEncryptedKey = pCanonical->pClientCert + cbClientCert;
CopyMemory(pCanonical->pbEncryptedKey, 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->pClientCert, pBuffer, pCanonical->ClientCertLen );
pBuffer += pCanonical->ClientCertLen;
pCanonical->pbResponse = pCanonical->pbEncryptedKey + cbEncryptedKey;
CopyMemory( pCanonical->pbResponse, pBuffer, pCanonical->ResponseLen );
*ppClient = pCanonical;
pInput->cbData = ReportedSize + sizeof(PCT1_MESSAGE_HEADER);
SP_RETURN( PCT_ERR_OK );
}
SP_STATUS
Pct1PackServerVerify(
PPct1_Server_Verify pCanonical,
PSPBuffer pCommOutput)
{
DWORD cbMessage;
PPCT1_SERVER_VERIFY pMessage;
PUCHAR pBuffer;
SP_BEGIN("Pct1PackServerVerify");
if(pCanonical == NULL || pCommOutput == NULL)
{
SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
}
pCommOutput->cbData = 0;
cbMessage = pCanonical->ResponseLen +
PCT_OFFSET_OF(PPCT1_SERVER_VERIFY, VariantData) -
sizeof(PCT1_MESSAGE_HEADER);
if (cbMessage > PCT_MAX_SHAKE_LEN)
{
SP_RETURN(PCT_INT_DATA_OVERFLOW);
}
pCommOutput->cbData = cbMessage + 2;
/* are we allocating our own memory? */
if(pCommOutput->pvBuffer == NULL)
{
pCommOutput->pvBuffer = SPExternalAlloc(pCommOutput->cbData);
if (NULL == pCommOutput->pvBuffer)
{
SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
}
pCommOutput->cbBuffer = pCommOutput->cbData;
}
if(pCommOutput->cbData > pCommOutput->cbBuffer)
{
// Required size returned in pCommOutput->cbData.
SP_RETURN(PCT_INT_BUFF_TOO_SMALL);
}
pMessage = pCommOutput->pvBuffer;
pMessage->MessageId = PCT1_MSG_SERVER_VERIFY;
pMessage->Header.Byte0 = MSBOF(cbMessage) | 0x80;
pMessage->Header.Byte1 = LSBOF(cbMessage);
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);
}
SP_RETURN( PCT_ERR_OK );
}
SP_STATUS
Pct1UnpackServerVerify(
PSPBuffer pInput,
PPct1_Server_Verify * ppServer)
{
PPct1_Server_Verify pCanonical;
PPCT1_SERVER_VERIFY pMessage;
PUCHAR pBuffer;
DWORD cbResponse;
DWORD ReportedSize;
SP_BEGIN("Pct1UnpackServerVerify");
if(pInput == NULL ||
ppServer == NULL ||
pInput->pvBuffer == NULL)
{
SP_RETURN(PCT_INT_INTERNAL_ERROR);
}
pMessage = pInput->pvBuffer;
if(pInput->cbData < 2)
{
pInput->cbData = 2;
SP_RETURN(PCT_INT_INCOMPLETE_MSG);
}
ReportedSize = SIZEOF(pMessage);
if(ReportedSize > PCT_MAX_SHAKE_LEN)
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
if ((ReportedSize+2) > pInput->cbData)
{
pInput->cbData = ReportedSize+2;
SP_RETURN(PCT_INT_INCOMPLETE_MSG);
}
if(ReportedSize < PCT_OFFSET_OF(PPCT1_SERVER_VERIFY, VariantData))
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
/* Verify Header: */
if (pMessage->MessageId != PCT1_MSG_SERVER_VERIFY )
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
*ppServer = NULL;
/* Verify Header: */
cbResponse = COMBINEBYTES(pMessage->ResponseLenMsb,
pMessage->ResponseLenLsb);
if (cbResponse > PCT_SESSION_ID_SIZE)
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
if ((PCT_OFFSET_OF(PPCT1_SERVER_VERIFY, VariantData) -
sizeof(PCT1_MESSAGE_HEADER) +
cbResponse ) !=
ReportedSize)
{
SP_RETURN(SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE));
}
pCanonical = (PPct1_Server_Verify)SPExternalAlloc( sizeof(Pct1_Server_Verify));
if (!pCanonical)
{
SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
}
/* 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;
pInput->cbData = ReportedSize + sizeof(PCT1_MESSAGE_HEADER);
SP_RETURN(PCT_ERR_OK);
}
SP_STATUS
Pct1PackError(
PPct1_Error pCanonical,
PSPBuffer pCommOutput)
{
DWORD cbMessage;
PPCT1_ERROR pMessage;
SP_BEGIN("Pct1PackError");
if(pCanonical == NULL || pCommOutput == NULL)
{
SP_RETURN(SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR));
}
pCommOutput->cbData = 0;
cbMessage = pCanonical->ErrInfoLen +
PCT_OFFSET_OF(PPCT1_ERROR, VariantData) -
sizeof(PCT1_MESSAGE_HEADER);
if (cbMessage > PCT_MAX_SHAKE_LEN)
{
SP_RETURN(SP_LOG_RESULT(PCT_INT_DATA_OVERFLOW));
}
pCommOutput->cbData = cbMessage+2;
/* are we allocating our own memory? */
if(pCommOutput->pvBuffer == NULL)
{
pCommOutput->pvBuffer = SPExternalAlloc(pCommOutput->cbData);
if (NULL == pCommOutput->pvBuffer)
{
SP_RETURN(SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY));
}
pCommOutput->cbBuffer = pCommOutput->cbData;
}
if(pCommOutput->cbData > pCommOutput->cbBuffer)
{
// Required size returned in pCommOutput->cbData.
SP_RETURN(PCT_INT_BUFF_TOO_SMALL);
}
pMessage = pCommOutput->pvBuffer;
pMessage->Header.Byte0 = MSBOF(cbMessage) | 0x80;
pMessage->Header.Byte1 = LSBOF(cbMessage);
pMessage->MessageId = PCT1_MSG_ERROR;
pMessage->ErrorMsb = MSBOF(pCanonical->Error);
pMessage->ErrorLsb = LSBOF(pCanonical->Error);
pMessage->ErrorInfoMsb = MSBOF(pCanonical->ErrInfoLen);
pMessage->ErrorInfoLsb = LSBOF(pCanonical->ErrInfoLen);
if(pCanonical->ErrInfoLen) {
CopyMemory(pMessage->VariantData, pCanonical->ErrInfo, pCanonical->ErrInfoLen);
}
SP_RETURN( PCT_ERR_OK );
}