|
|
//+-------------------------------------------------------------------------
//
// 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);
if ((dwOffset + strlen(SPC_LINK_OBJID) + 1 + dwRetLen + strlen(pSI->DigestAlgorithm.pszObjId) + 1 + cbDigest) > ((DWORD_PTR) psData) + *pdwDLen) { goto ErrorReturn; }
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, *pcbCert - OFFSETOF(WIN_CERTIFICATE, 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); } }
if (pWinCert != NULL) { 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, DWORD cb) { //
// 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); }
if (cb < 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;
if (Para.Hdr.cfres.cbCFHeader < (RESERVE_CNT_HDR_LEN + Para.Hdr.cbJunk + sizeof(CABSignatureStruct_))) { return(FALSE); } 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); }
if (Para.Hdr.cfres.cbCFHeader < (RESERVE_CNT_HDR_LEN + Para.Hdr.cbJunk + cbSignedData)) { 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 (0 != Para.Hdr.cfres.cbCFFolder || 0 != Para.Hdr.cfres.cbCFData) { // Since these 2 lengths aren't included in the hash and
// aren't used for Microsoft signed cabs, don't allow them to be
// set.
goto BadCABFormat; }
if (Para.Hdr.cfres.cbCFHeader > 0) { if (this->cbFileMap < (cbOffset + Para.Hdr.cfres.cbCFHeader)) { goto BadCABFormat; }
if (Para.Hdr.pbReserve = (BYTE *)this->SIPNew(Para.Hdr.cfres.cbCFHeader)) {
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) { goto BadCABFormat; } else { 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
|