windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/pkitrust/mssip32/sipobjcb.cpp
2020-09-26 16:20:57 +08:00

1313 lines
33 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: SIPObjCB.cpp (CAB)
//
// Contents: Microsoft SIP Provider
//
// History: 15-Feb-1997 pberkman created
//
//--------------------------------------------------------------------------
#include "global.hxx"
#include "sipobjcb.hxx"
#include "sha.h"
#include "md5.h"
////////////////////////////////////////////////////////////////////////////
//
// construct/destruct:
//
SIPObjectCAB_::SIPObjectCAB_(DWORD id) : SIPObject_(id)
{
memset(&Para, 0x00, sizeof(CAB_PARA));
fUseV1Sig = FALSE;
}
SIPObjectCAB_::~SIPObjectCAB_(void)
{
FreeHeader();
}
////////////////////////////////////////////////////////////////////////////
//
// public:
//
BOOL SIPObjectCAB_::RemoveSignedDataMsg(SIP_SUBJECTINFO *pSI,DWORD dwIdx)
{
if (this->FileHandleFromSubject(pSI, GENERIC_READ | GENERIC_WRITE))
{
return(this->RemoveCertificate(dwIdx));
}
return(FALSE);
}
BOOL SIPObjectCAB_::CreateIndirectData(SIP_SUBJECTINFO *pSI,DWORD *pdwDLen,
SIP_INDIRECT_DATA *psData)
{
BOOL fRet;
BYTE *pbDigest;
BYTE *pbAttrData;
SPC_LINK SpcLink;
DWORD cbDigest;
HCRYPTPROV hProvT;
pbDigest = NULL;
pbAttrData = NULL;
fRet = TRUE;
hProvT = pSI->hProv;
if (!(hProvT))
{
if (!(this->LoadDefaultProvider()))
{
goto GetProviderFailed;
}
hProvT = this->hProv;
}
memset(&SpcLink,0x00,sizeof(SPC_LINK));
SpcLink.dwLinkChoice = SPC_FILE_LINK_CHOICE;
SpcLink.pwszFile = OBSOLETE_TEXT_W;
if (!(psData))
{
HCRYPTHASH hHash;
DWORD dwRetLen;
DWORD dwEncLen;
DWORD dwAlgId;
dwRetLen = sizeof(SIP_INDIRECT_DATA);
// crypt_algorithm_identifier...
// obj id
dwRetLen += strlen(pSI->DigestAlgorithm.pszObjId);
dwRetLen += 1; // null term.
// parameters (none)...
// crypt_attribute_type_value size...
dwRetLen += strlen(this->GetDataObjectID());
dwRetLen += 1; // null term.
// size of the value
dwEncLen = 0;
CryptEncodeObject( PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
this->GetDataOIDHint(),
&SpcLink,
NULL,
&dwEncLen);
if (dwEncLen < 1)
{
goto EncodeError;
}
dwRetLen += dwEncLen;
if ((dwAlgId = CertOIDToAlgId(pSI->DigestAlgorithm.pszObjId)) == 0)
{
goto BadAlgId;
}
switch (dwAlgId)
{
case CALG_MD5:
cbDigest = MD5DIGESTLEN;
break;
case CALG_SHA1:
cbDigest = A_SHA_DIGEST_LEN;
break;
default:
if (!(CryptCreateHash(hProvT, dwAlgId, NULL, 0, &hHash)))
{
goto CreateHashFailed;
}
// just to get hash length
if (!(CryptHashData(hHash,(const BYTE *)" ",1,0)))
{
CryptDestroyHash(hHash);
goto HashDataFailed;
}
cbDigest = 0;
CryptGetHashParam(hHash, HP_HASHVAL, NULL, &cbDigest,0);
CryptDestroyHash(hHash);
}
dwRetLen += cbDigest;
*pdwDLen = dwRetLen;
goto CommonReturn;
}
if (!(this->FileHandleFromSubject(pSI, (pSI->dwFlags & MSSIP_FLAGS_PROHIBIT_RESIZE_ON_CREATE) ?
GENERIC_READ : (GENERIC_READ | GENERIC_WRITE))))
{
goto SubjectFileFailure;
}
//
// version 1 had the signature in the header. We want
// the signature at the end and our structure in the
// header where the signature used to be. -- check it.
//
if (!(pSI->dwFlags & MSSIP_FLAGS_PROHIBIT_RESIZE_ON_CREATE))
{
if (!(this->ReadHeader()))
{
goto ReadHeaderFailed;
}
if (!(this->ReserveSignedData(sizeof(CABSignatureStruct_))))
{
goto ReserveDataFailed;
}
if (!(this->MapFile()))
{
goto MapFileFailed;
}
}
if (!(pbDigest = this->DigestFile(hProvT, 0, pSI->DigestAlgorithm.pszObjId, &cbDigest)))
{
goto DigestFileFailed;
}
DWORD_PTR dwOffset;
DWORD dwRetLen;
dwRetLen = 0;
CryptEncodeObject(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, this->GetDataOIDHint(), &SpcLink,
NULL, &dwRetLen);
if (dwRetLen < 1)
{
goto EncodeError;
}
if (!(pbAttrData = (BYTE *)this->SIPNew(dwRetLen)))
{
goto MemoryError;
}
if (!(CryptEncodeObject(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, this->GetDataOIDHint(), &SpcLink,
pbAttrData, &dwRetLen)))
{
goto EncodeError;
}
dwOffset = (DWORD_PTR)psData + sizeof(SIP_INDIRECT_DATA);
strcpy((char *)dwOffset, this->GetDataObjectID());
psData->Data.pszObjId = (LPSTR)dwOffset;
dwOffset += (strlen(SPC_LINK_OBJID) + 1);
memcpy((void *)dwOffset, pbAttrData,dwRetLen);
psData->Data.Value.pbData = (BYTE *)dwOffset;
psData->Data.Value.cbData = dwRetLen;
dwOffset += dwRetLen;
strcpy((char *)dwOffset, (char *)pSI->DigestAlgorithm.pszObjId);
psData->DigestAlgorithm.pszObjId = (char *)dwOffset;
psData->DigestAlgorithm.Parameters.cbData = 0;
psData->DigestAlgorithm.Parameters.pbData = NULL;
dwOffset += (strlen(pSI->DigestAlgorithm.pszObjId) + 1);
memcpy((void *)dwOffset,pbDigest,cbDigest);
psData->Digest.pbData = (BYTE *)dwOffset;
psData->Digest.cbData = cbDigest;
CommonReturn:
if (pbDigest)
{
delete pbDigest;
}
if (pbAttrData)
{
delete pbAttrData;
}
return(fRet);
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR_EX(DBG_SS, EncodeError);
TRACE_ERROR_EX(DBG_SS, SubjectFileFailure);
TRACE_ERROR_EX(DBG_SS, HashDataFailed);
TRACE_ERROR_EX(DBG_SS, CreateHashFailed);
TRACE_ERROR_EX(DBG_SS, ReadHeaderFailed);
TRACE_ERROR_EX(DBG_SS, ReserveDataFailed);
TRACE_ERROR_EX(DBG_SS, MapFileFailed);
TRACE_ERROR_EX(DBG_SS, DigestFileFailed);
TRACE_ERROR_EX(DBG_SS, GetProviderFailed);
SET_ERROR_VAR_EX(DBG_SS, MemoryError, ERROR_NOT_ENOUGH_MEMORY);
SET_ERROR_VAR_EX(DBG_SS, BadAlgId, NTE_BAD_ALGID);
}
////////////////////////////////////////////////////////////////////////////
//
// protected:
//
BOOL SIPObjectCAB_::GetMessageFromFile(SIP_SUBJECTINFO *pSI,
WIN_CERTIFICATE *pWinCert,
DWORD dwIndex,DWORD *pcbCert)
{
DWORD cbCert;
if (dwIndex != 0)
{
goto InvalidParam;
}
if (!(this->ReadHeader()))
{
goto ReadHeaderFailed;
}
if (Para.Hdr.cbSig == 0)
{
goto NoSignature;
}
if (!(fUseV1Sig))
{
//
// Version 2 header
//
cbCert = OFFSETOF(WIN_CERTIFICATE, bCertificate) +
Para.Hdr.pCabSigStruct->cbSig;
if (*pcbCert < cbCert)
{
*pcbCert = cbCert;
goto BufferTooSmall;
}
if (pWinCert)
{
if (!(this->ReadSignedData(pWinCert->bCertificate)))
{
goto ReadSignedFailed;
}
}
}
else
{
//
// Version 1 header
//
cbCert = OFFSETOF(WIN_CERTIFICATE, bCertificate) + Para.Hdr.cbSig;
if (*pcbCert < cbCert)
{
*pcbCert = cbCert;
goto BufferTooSmall;
}
if (pWinCert)
{
BYTE *pbSignedData;
pbSignedData = Para.Hdr.pbReserve + RESERVE_CNT_HDR_LEN + Para.Hdr.cbJunk;
pWinCert->wRevision = WIN_CERT_REVISION_1_0;
memcpy(pWinCert->bCertificate, pbSignedData, Para.Hdr.cbSig);
}
}
pWinCert->dwLength = cbCert;
pWinCert->wCertificateType = WIN_CERT_TYPE_PKCS_SIGNED_DATA;
return(TRUE);
ErrorReturn:
return(FALSE);
TRACE_ERROR_EX(DBG_SS, ReadHeaderFailed);
TRACE_ERROR_EX(DBG_SS, ReadSignedFailed);
SET_ERROR_VAR_EX(DBG_SS, InvalidParam, ERROR_INVALID_PARAMETER);
SET_ERROR_VAR_EX(DBG_SS, BufferTooSmall,ERROR_INSUFFICIENT_BUFFER);
SET_ERROR_VAR_EX(DBG_SS, NoSignature, TRUST_E_NOSIGNATURE);
}
BOOL SIPObjectCAB_::PutMessageInFile(SIP_SUBJECTINFO *pSI,
WIN_CERTIFICATE *pWinCert,DWORD *pdwIndex)
{
if ((pWinCert->dwLength <= OFFSETOF(WIN_CERTIFICATE,bCertificate)) ||
(pWinCert->wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA))
{
SetLastError((DWORD)ERROR_INVALID_PARAMETER);
return(FALSE);
}
if (this->ReadHeader())
{
if (!(fUseV1Sig))
{
//
// version 2
//
if (this->WriteSignedData((BYTE *)&(pWinCert->bCertificate),
pWinCert->dwLength -
OFFSETOF(WIN_CERTIFICATE, bCertificate)))
{
return(TRUE);
}
}
else
{
//
// version 1
//
DWORD dwCheck;
DWORD cbSignedData;
cbSignedData = pWinCert->dwLength - OFFSETOF(WIN_CERTIFICATE, bCertificate);
dwCheck = RESERVE_LEN_ALIGN(RESERVE_CNT_HDR_LEN + Para.Hdr.cbJunk + cbSignedData) -
Para.Hdr.cfres.cbCFHeader;
if (dwCheck > 0)
{
SetLastError(CRYPT_E_FILERESIZED);
return(FALSE);
}
if (WriteSignedDataV1((PBYTE)&(pWinCert->bCertificate), cbSignedData))
{
return(TRUE);
}
}
}
return(FALSE);
}
BOOL SIPObjectCAB_::GetDigestStream(DIGEST_DATA *pDigestData,
DIGEST_FUNCTION pfnCallBack, DWORD dwFlags)
{
if (dwFlags != 0)
{
goto InvalidParam;
}
if (!(this->ReadHeader()))
{
goto ReadHeaderFailed;
}
if (!(this->DigestHeader(pfnCallBack, pDigestData)))
{
goto DigestFailed;
}
DWORD cbRemain;
cbRemain = this->cbFileMap - Para.Hdr.cbTotalHdr;
if (!(fUseV1Sig) && (Para.Hdr.pCabSigStruct))
{
cbRemain -= Para.Hdr.pCabSigStruct->cbSig;
}
if ((Para.Hdr.cfheader.cbCabinet - Para.Hdr.cbTotalHdr) != cbRemain)
{
goto BadFileFormat;
}
if (this->cbFileMap < (Para.Hdr.cbTotalHdr + cbRemain))
{
goto BadFileFormat;
}
__try {
if (!(pfnCallBack(pDigestData, &this->pbFileMap[Para.Hdr.cbTotalHdr], cbRemain)))
{
goto HashFailed;
}
}
__except(EXCEPTION_EXECUTE_HANDLER) {
SetLastError(GetExceptionCode());
goto HashFailed;
}
return(TRUE);
ErrorReturn:
return(FALSE);
TRACE_ERROR_EX(DBG_SS, DigestFailed);
TRACE_ERROR_EX(DBG_SS, ReadHeaderFailed);
TRACE_ERROR_EX(DBG_SS, HashFailed);
SET_ERROR_VAR_EX(DBG_SS, InvalidParam, ERROR_INVALID_PARAMETER);
SET_ERROR_VAR_EX(DBG_SS, BadFileFormat, ERROR_BAD_FORMAT);
}
////////////////////////////////////////////////////////////////////////////
//
// private:
//
BOOL SIPObjectCAB_::RemoveCertificate(DWORD Index)
{
return(FALSE); // not yet!!! Currently, we only support 1.
# ifdef _DONT_USE_YET
BYTE *pbFolders;
DWORD cbFolders;
BYTE *pbReserve;
USHORT cbReserve;
if (Index != 0)
{
SetLastError((DWORD)ERROR_INVALID_PARAMETER);
return(FALSE);
}
pbFolders = NULL;
cbFolders = 0;
Para.dwFlags = VERIFY_CAB_FLAG;
if (this->ReadHeader())
{
if (Para.Hdr.cbSig <= (RESERVE_CNT_HDR_LEN + Para.Hdr.cbJunk))
{
SetLastError((DWORD)CRYPT_E_NO_MATCH);
return(FALSE);
}
long lShift;
if (Para.Hdr.cbJunk)
{
lShift = Para.Hdr.cbSig;
if (Para.Hdr.pbReserve)
{
*((USHORT *)Para.Hdr.pbReserve) = Para.Hdr.cbJunk;
*((USHORT *)(Para.Hdr.pbReserve + sizeof(USHORT))) = 0; // no more sig
}
}
else
{
lShift = Para.Hdr.cbSig + (sizeof(USHORT) * 2);
Para.Hdr.cfheader.flags &= ~(cfhdrRESERVE_PRESENT);
if (Para.Hdr.pbReserve)
{
delete Para.Hdr.pbReserve;
Para.Hdr.pbReserve = NULL;
}
}
Para.Hdr.cbSig = 0;
Para.Hdr.cfres.cbCFHeader -= (USHORT)lShift; // subtract the amount we want to shrink.
// adjust the header offsets
if (this->ShiftFileBytes(lShift))
{
Para.Hdr.cbTotalHdr -= lShift;
Para.Hdr.cfheader.cbCabinet -= lShift;
Para.Hdr.cfheader.coffFiles -= lShift;
}
// redo checksums....
this->ChecksumHeader();
if (this->WriteHeader())
{
// We need to read in the folders to adjust their CFDATA file offset
if (Para.Hdr.cfheader.cFolders)
{
if (SetFilePointer(this->hFile,
Para.Hdr.cbTotalHdr + lShift,
NULL, FILE_BEGIN) == 0xFFFFFFFF)
{
return(FALSE);
}
USHORT cFolders;
LONG cbFolder;
cFolders = Para.Hdr.cfheader.cFolders;
cbFolder = sizeof(CFFOLDER) + Para.Hdr.cfres.cbCFFolder;
cbFolders = cbFolder * cFolders;
if (!(pbFolders = (BYTE *)this->SIPNew(cbFolders)))
{
return(FALSE);
}
DWORD cbFile;
if (!(ReadFile(this->hFile, pbFolders, cbFolders, &cbFile, NULL)) ||
(cbFile != cbFolders))
{
delete pbFolders;
SetLastError(ERROR_BAD_FORMAT);
return(FALSE);
}
BYTE *pb;
pb = pbFolders;
while (cFolders > 0)
{
((CFFOLDER *)pb)->coffCabStart -= lShift;
pb += cbFolder;
cFolders--;
}
// back up and write!
if (SetFilePointer(this->hFile, -((LONG)cbFolders),
NULL, FILE_CURRENT) == 0xFFFFFFFF)
{
delete pbFolders;
return(FALSE);
}
if (!(WriteFile(this->hFile, pbFolders, cbFolders, &cbFile, NULL)) ||
(cbFile != cbFolders))
{
delete pbFolders;
return(FALSE);
}
delete pbFolders;
}
return(TRUE);
}
}
return(FALSE);
# endif // _DONT_USE_YET
}
BOOL SIPObjectCAB_::ReadSignedData(BYTE *pbRet)
{
//
// this function is NOT called for version 1 Sigs!
//
if (Para.Hdr.pCabSigStruct->cbFileOffset != (DWORD)Para.Hdr.cfheader.cbCabinet)
{
SetLastError((DWORD)TRUST_E_NOSIGNATURE);
return(FALSE);
}
if (this->cbFileMap < (Para.Hdr.pCabSigStruct->cbFileOffset +
Para.Hdr.pCabSigStruct->cbSig))
{
SetLastError(ERROR_BAD_FORMAT);
return(FALSE);
}
__try {
memcpy(pbRet, &this->pbFileMap[Para.Hdr.pCabSigStruct->cbFileOffset], Para.Hdr.pCabSigStruct->cbSig);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
SetLastError(GetExceptionCode());
return(FALSE);
}
return(TRUE);
}
BOOL SIPObjectCAB_::WriteSignedData(BYTE *pbSig, DWORD cbSig)
{
//
// this function is NOT called for version 1 Sigs!
//
if (!(pbSig) || (cbSig == 0))
{
return(FALSE);
}
CABSignatureStruct_ sSig;
memset(&sSig, 0x00, sizeof(CABSignatureStruct_));
sSig.cbFileOffset = Para.Hdr.cfheader.cbCabinet;
sSig.cbSig = cbSig;
memcpy(Para.Hdr.pbReserve + RESERVE_CNT_HDR_LEN + Para.Hdr.cbJunk,
&sSig, sizeof(CABSignatureStruct_));
if (!(this->WriteHeader()))
{
return(FALSE);
}
if (SetFilePointer(this->hFile, Para.Hdr.cfheader.cbCabinet, NULL, FILE_BEGIN) == 0xFFFFFFFF)
{
return(FALSE);
}
DWORD cbWritten;
if (!(WriteFile(this->hFile, pbSig, cbSig, &cbWritten, NULL)) ||
(cbWritten != cbSig))
{
return(FALSE);
}
this->UnmapFile();
SetEndOfFile(this->hFile); // signature is the LAST thing!!!
return(this->MapFile());
}
BOOL SIPObjectCAB_::WriteSignedDataV1(BYTE *pbSignedData, DWORD cbSignedData)
{
if (!(pbSignedData) || (cbSignedData == 0))
{
return(FALSE);
}
memcpy(Para.Hdr.pbReserve + RESERVE_CNT_HDR_LEN + Para.Hdr.cbJunk,
pbSignedData, cbSignedData);
Para.Hdr.cbSig = (USHORT)cbSignedData;
ChecksumHeader();
return(this->WriteHeader());
}
BOOL SIPObjectCAB_::ReadHeader(void)
{
DWORD cbOffset;
BOOL fRet;
this->FreeHeader();
if (this->cbFileMap < sizeof(Para.Hdr.cfheader))
{
goto BadCABFormat;
}
__try {
memcpy(&Para.Hdr.cfheader, &this->pbFileMap[0], sizeof(Para.Hdr.cfheader));
cbOffset = sizeof(Para.Hdr.cfheader);
if (Para.Hdr.cfheader.sig != sigCFHEADER)
{
goto BadCABFormat;
}
if (Para.Hdr.cfheader.flags & cfhdrRESERVE_PRESENT)
{
if (this->cbFileMap < (cbOffset + sizeof(Para.Hdr.cfres)))
{
goto BadCABFormat;
}
memcpy(&Para.Hdr.cfres, &this->pbFileMap[cbOffset], sizeof(Para.Hdr.cfres));
cbOffset += sizeof(Para.Hdr.cfres);
Para.Hdr.cbcfres = sizeof(Para.Hdr.cfres);
if (Para.Hdr.cfres.cbCFHeader > 0)
{
if (Para.Hdr.pbReserve = (BYTE *)this->SIPNew(Para.Hdr.cfres.cbCFHeader))
{
if (this->cbFileMap < (cbOffset + Para.Hdr.cfres.cbCFHeader))
{
goto BadCABFormat;
}
memcpy(Para.Hdr.pbReserve, &this->pbFileMap[cbOffset], Para.Hdr.cfres.cbCFHeader);
cbOffset += Para.Hdr.cfres.cbCFHeader;
if (Para.Hdr.cfres.cbCFHeader >= RESERVE_CNT_HDR_LEN)
{
Para.Hdr.cbJunk = *((USHORT *)Para.Hdr.pbReserve);
Para.Hdr.cbSig = *((USHORT *)(Para.Hdr.pbReserve + sizeof(USHORT)));
if (RESERVE_CNT_HDR_LEN + Para.Hdr.cbJunk + Para.Hdr.cbSig > Para.Hdr.cfres.cbCFHeader)
{
goto BadCABFormat;
}
if (Para.Hdr.cbSig == sizeof(CABSignatureStruct_))
{
fUseV1Sig = FALSE;
Para.Hdr.pCabSigStruct = (CABSignatureStruct_ *)(Para.Hdr.pbReserve +
RESERVE_CNT_HDR_LEN +
Para.Hdr.cbJunk);
}
else
{
fUseV1Sig = TRUE;
}
}
}
}
}
DWORD cStrings;
DWORD cb;
cStrings = 0;
if (Para.Hdr.cfheader.flags & cfhdrPREV_CABINET)
{
cStrings += 2;
}
if (Para.Hdr.cfheader.flags & cfhdrNEXT_CABINET)
{
cStrings += 2;
}
if (cStrings > 0)
{
// First read to get total length of all the strings
cb = 0;
for (; cStrings > 0; cStrings--)
{
while (this->pbFileMap[cbOffset + cb])
{
cb++;
if (this->cbFileMap < (cbOffset + cb))
{
goto BadCABFormat;
}
}
//Increment the counter for the NULL terminator
cb++;
}
if (!(Para.Hdr.pbStrings = new BYTE[cb]))
{
goto MemoryError;
}
Para.Hdr.cbStrings = cb;
memcpy(Para.Hdr.pbStrings, &this->pbFileMap[cbOffset], cb);
cbOffset += cb;
}
Para.Hdr.cbTotalHdr = sizeof(Para.Hdr.cfheader) + Para.Hdr.cbcfres +
Para.Hdr.cfres.cbCFHeader + Para.Hdr.cbStrings;
if ((long)Para.Hdr.cbTotalHdr > Para.Hdr.cfheader.cbCabinet)
{
goto BadCABFormat;
}
fRet = TRUE;
}
__except(EXCEPTION_EXECUTE_HANDLER) {
SetLastError(GetExceptionCode());
goto ErrorReturn;
}
CommonReturn:
return(fRet);
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR_EX(DBG_SS, BadCABFormat, ERROR_BAD_FORMAT);
SET_ERROR_VAR_EX(DBG_SS, MemoryError, ERROR_NOT_ENOUGH_MEMORY);
}
void SIPObjectCAB_::FreeHeader(void)
{
DELETE_OBJECT(Para.Hdr.pbReserve);
DELETE_OBJECT(Para.Hdr.pbStrings);
memset(&Para, 0x00, sizeof(CAB_PARA));
}
BOOL SIPObjectCAB_::WriteHeader(void)
{
DWORD cbWritten;
// Position at beginning of file
if (SetFilePointer(this->hFile, 0, NULL, FILE_BEGIN) == 0xFFFFFFFF)
{
return(FALSE);
}
if (!(WriteFile(this->hFile, &Para.Hdr.cfheader, sizeof(Para.Hdr.cfheader),
&cbWritten, NULL)) ||
(cbWritten != sizeof(Para.Hdr.cfheader)))
{
return(FALSE);
}
if (Para.Hdr.cbcfres)
{
if (!(WriteFile(this->hFile, &Para.Hdr.cfres, sizeof(Para.Hdr.cfres),
&cbWritten, NULL)) ||
(cbWritten != sizeof(Para.Hdr.cfres)))
{
return(FALSE);
}
if (Para.Hdr.pbReserve)
{
*((USHORT *)(Para.Hdr.pbReserve + sizeof(USHORT))) = Para.Hdr.cbSig;
if (!(WriteFile(this->hFile, Para.Hdr.pbReserve, Para.Hdr.cfres.cbCFHeader,
&cbWritten, NULL)) ||
(cbWritten != Para.Hdr.cfres.cbCFHeader))
{
return(FALSE);
}
}
}
if (Para.Hdr.pbStrings)
{
if (!(WriteFile(this->hFile, Para.Hdr.pbStrings, Para.Hdr.cbStrings,
&cbWritten, NULL)) ||
(cbWritten != Para.Hdr.cbStrings))
{
return(FALSE);
}
}
return(TRUE);
}
BOOL SIPObjectCAB_::ShiftFileBytes(LONG lbShift)
{
LONG lStartOffset;
LONG lEndOffset;
LONG lNewEndOffset;
LONG cbTotalMove;
LONG cbMove;
lStartOffset = SetFilePointer(this->hFile, 0, NULL, FILE_CURRENT);
lEndOffset = (LONG)this->cbFileMap;
lNewEndOffset = lEndOffset + lbShift;
cbTotalMove = lEndOffset - lStartOffset;
BYTE szMove[512];
while (cbTotalMove)
{
cbMove = min(cbTotalMove, sizeof(szMove));
if (lbShift > 0)
{
if (!(SeekAndReadFile(lEndOffset - cbMove, &szMove[0], cbMove)))
{
return(FALSE);
}
if (!(SeekAndWriteFile((lEndOffset - cbMove) + lbShift, &szMove[0], cbMove)))
{
return(FALSE);
}
lEndOffset -= cbMove;
}
else if (lbShift < 0)
{
if (!(SeekAndReadFile(lStartOffset, &szMove[0], cbMove)))
{
return(FALSE);
}
if (!(SeekAndWriteFile(lStartOffset + lbShift, &szMove[0], cbMove)))
{
return(FALSE);
}
lStartOffset += cbMove;
}
cbTotalMove -= cbMove;
}
//
// Set end of file
//
if (SetFilePointer(this->hFile, lNewEndOffset, NULL, FILE_BEGIN) == 0xFFFFFFFF)
{
return(FALSE);
}
this->UnmapFile();
SetEndOfFile(this->hFile);
return(this->MapFile());
}
BOOL SIPObjectCAB_::ReserveSignedData(DWORD cbSignedData)
{
LONG lbShift;
USHORT cbReserve;
if (cbSignedData != sizeof(CABSignatureStruct_))
{
return(FALSE);
}
if (SetFilePointer(this->hFile, Para.Hdr.cbTotalHdr, NULL, FILE_BEGIN) == 0xFFFFFFFF)
{
return(FALSE);
}
fUseV1Sig = FALSE;
//
// Calculate length needed for CFRESERVE's abReserve[] and allocate
//
cbReserve = (USHORT)(RESERVE_LEN_ALIGN(RESERVE_CNT_HDR_LEN +
Para.Hdr.cbJunk + cbSignedData));
//
// Calculate number of bytes to grow or shrink the cab file
//
lbShift = cbReserve - Para.Hdr.cfres.cbCFHeader;
//
// we're alread a v1 cab!
//
if (lbShift == 0)
{
return(TRUE);
}
BYTE *pbReserve;
BYTE *pbFolders;
DWORD cbFolders;
pbFolders = NULL;
cbFolders = 0;
if (!(pbReserve = (BYTE *)this->SIPNew(cbReserve)))
{
return(FALSE);
}
memset(pbReserve, 0x00, cbReserve);
//
// Update allocated abReserve[] with counts and old junk
//
if (Para.Hdr.cbJunk)
{
*((USHORT *)pbReserve) = Para.Hdr.cbJunk;
memcpy(pbReserve + RESERVE_CNT_HDR_LEN,
Para.Hdr.pbReserve + RESERVE_CNT_HDR_LEN, Para.Hdr.cbJunk);
}
*((USHORT *)(pbReserve + sizeof(USHORT))) = (USHORT)cbSignedData;
//
// Update Hdr's CFRESERVE abReserve[] to reflect above changes
//
if (Para.Hdr.pbReserve)
{
delete Para.Hdr.pbReserve;
Para.Hdr.pbReserve = NULL;
}
Para.Hdr.pbReserve = pbReserve;
Para.Hdr.cfres.cbCFHeader = cbReserve;
Para.Hdr.cbSig = (USHORT)cbSignedData;
if (Para.Hdr.cbcfres == 0)
{
// Need to add CFRESERVE record
Para.Hdr.cfheader.flags |= cfhdrRESERVE_PRESENT;
Para.Hdr.cbcfres = sizeof(CFRESERVE);
lbShift += sizeof(CFRESERVE);
}
//
// We need to read in the folders to adjust their CFDATA file offset
//
if (Para.Hdr.cfheader.cFolders)
{
USHORT cFolders;
LONG cbFolder;
BYTE *pb;
DWORD cbRead;
cFolders = Para.Hdr.cfheader.cFolders;
cbFolder = sizeof(CFFOLDER) + Para.Hdr.cfres.cbCFFolder;
cbFolders = cbFolder * cFolders;
if (!(pbFolders = (BYTE *)this->SIPNew(cbFolders)))
{
return(FALSE);
}
if (!(ReadFile(this->hFile, pbFolders, cbFolders, &cbRead, NULL)) ||
(cbRead != cbFolders))
{
delete pbFolders;
SetLastError(ERROR_BAD_FORMAT);
return(FALSE);
}
pb = pbFolders;
for (; cFolders > 0; cFolders--, pb += cbFolder)
{
((CFFOLDER *) pb)->coffCabStart += lbShift;
}
}
//
// We need to shift the remaining contents of the cab file (CFFILE (s)
// and CFDATA (s)) by lbShift
//
if (!(ShiftFileBytes(lbShift)))
{
if (pbFolders)
{
delete pbFolders;
}
return(FALSE);
}
//
// Update lengths and offsets in the header by the delta shift needed
// to store the signed data.
//
Para.Hdr.cbTotalHdr += lbShift;
Para.Hdr.cfheader.cbCabinet += lbShift;
Para.Hdr.cfheader.coffFiles += lbShift;
//
// pberkman - if someone starts using these, we don't want to mess them up!!!
//
// Para.Hdr.cfheader.csumHeader = 0;
// Para.Hdr.cfheader.csumFolders = 0;
// Para.Hdr.cfheader.csumFiles = 0;
//
// Write the header and folders back to the cab file
//
if (!(this->WriteHeader()))
{
if (pbFolders)
{
delete pbFolders;
}
return(FALSE);
}
if (pbFolders)
{
DWORD cbWritten;
cbWritten = 0;
if (!(WriteFile(this->hFile, pbFolders, cbFolders, &cbWritten, NULL)) ||
(cbWritten != cbFolders))
{
delete pbFolders;
return(FALSE);
}
delete pbFolders;
}
return(TRUE);
}
BOOL SIPObjectCAB_::DigestHeader(DIGEST_FUNCTION pfnDigestData, DIGEST_HANDLE hDigestData)
{
//
// Digest CFHEADER, skipping the csumHeader field
//
if (!(pfnDigestData(hDigestData, (BYTE *)&Para.Hdr.cfheader.sig,
sizeof(Para.Hdr.cfheader.sig))))
{
return(FALSE);
}
if (!(pfnDigestData(hDigestData, (BYTE *)&Para.Hdr.cfheader.cbCabinet,
sizeof(CFHEADER) - sizeof(Para.Hdr.cfheader.sig) - sizeof(CHECKSUM))))
{
return(FALSE);
}
if (Para.Hdr.cbcfres)
{
// skip the cfres itself!
if (Para.Hdr.cfres.cbCFHeader >= RESERVE_CNT_HDR_LEN)
{
// Digest any "junk" in abReserve[] before the signature
if (!(pfnDigestData(hDigestData, (BYTE *)&Para.Hdr.cbJunk,
sizeof(Para.Hdr.cbJunk))))
{
return(FALSE);
}
if (Para.Hdr.cbJunk)
{
if (!(pfnDigestData(hDigestData,
Para.Hdr.pbReserve + RESERVE_CNT_HDR_LEN,
Para.Hdr.cbJunk)))
{
return(FALSE);
}
}
}
}
if (Para.Hdr.pbStrings)
{
// Digest the strings
if (!(pfnDigestData(hDigestData, Para.Hdr.pbStrings, Para.Hdr.cbStrings)))
{
return(FALSE);
}
}
return(TRUE);
}
void SIPObjectCAB_::ChecksumHeader(void)
{
return;
// version 1 set checksum to zero. this seems to be the correct thing to do????
# ifdef _DONT_USE_YET
CHECKSUM csum = 0;
if (Para.Hdr.cfheader.csumHeader == 0)
{
return;
}
// Checksum CFHEADER, skipping the csumHeader field
csum = CSUMCompute(&Para.Hdr.cfheader.sig, sizeof(Para.Hdr.cfheader.sig), csum);
csum = CSUMCompute(&Para.Hdr.cfheader.cbCabinet,
sizeof(CFHEADER) -
sizeof(Para.Hdr.cfheader.sig) -
sizeof(CHECKSUM),
csum);
if (Para.Hdr.cbcfres)
{
csum = CSUMCompute(&Para.Hdr.cfres, sizeof(Para.Hdr.cfres), csum);
if (Para.Hdr.pbReserve)
{
csum = CSUMCompute(Para.Hdr.pbReserve, Para.Hdr.cfres.cbCFHeader, csum);
}
}
if (Para.Hdr.pbStrings)
{
csum = CSUMCompute(Para.Hdr.pbStrings, Para.Hdr.cbStrings, csum);
}
Para.Hdr.cfheader.csumHeader = csum;
# endif
}
#ifdef _DONT_USE_YET
CHECKSUM SIPObjectCAB_::CSUMCompute(void *pv, UINT cb, CHECKSUM seed)
{
int cUlong; // Number of ULONGs in block
CHECKSUM csum; // Checksum accumulator
BYTE *pb;
ULONG ul;
cUlong = cb / 4; // Number of ULONGs
csum = seed; // Init checksum
pb = (BYTE*)pv; // Start at front of data block
//** Checksum integral multiple of ULONGs
while (cUlong-- > 0) {
//** NOTE: Build ULONG in big/little-endian independent manner
ul = *pb++; // Get low-order byte
ul |= (((ULONG)(*pb++)) << 8); // Add 2nd byte
ul |= (((ULONG)(*pb++)) << 16); // Add 3nd byte
ul |= (((ULONG)(*pb++)) << 24); // Add 4th byte
csum ^= ul; // Update checksum
}
//** Checksum remainder bytes
ul = 0;
switch (cb % 4) {
case 3:
ul |= (((ULONG)(*pb++)) << 16); // Add 3nd byte
case 2:
ul |= (((ULONG)(*pb++)) << 8); // Add 2nd byte
case 1:
ul |= *pb++; // Get low-order byte
default:
break;
}
csum ^= ul; // Update checksum
//** Return computed checksum
return csum;
}
#endif // _DONT_USE_YET