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.
976 lines
30 KiB
976 lines
30 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: jvimage.cpp
|
|
//
|
|
// Contents: Microsoft SIP Provider (JAVA utilities)
|
|
//
|
|
// History: 15-Feb-1997 pberkman created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "global.hxx"
|
|
|
|
BOOL SeekAndReadFile(HANDLE hFile, DWORD lFileOffset,BYTE *pb,
|
|
DWORD cb);
|
|
|
|
BOOL SeekAndWriteFile(HANDLE hFile, DWORD lFileOffset, BYTE *pb,
|
|
DWORD cb);
|
|
|
|
typedef void *HSHPDIGESTDATA;
|
|
typedef BOOL (WINAPI *PFN_SHP_DIGEST_DATA)(HSHPDIGESTDATA hDigestData,
|
|
BYTE *pbData,
|
|
DWORD cbData);
|
|
|
|
typedef void *HSHPSIGNFILE;
|
|
|
|
|
|
typedef struct _JAVA_OPEN_ARG
|
|
{
|
|
HANDLE hFile;
|
|
} JAVA_OPEN_ARG, *PJAVA_OPEN_ARG;
|
|
|
|
|
|
typedef struct _JAVA_FUNC_PARA
|
|
{
|
|
HANDLE hFile;
|
|
BYTE *pbSignedData;
|
|
} JAVA_FUNC_PARA, *PJAVA_FUNC_PARA;
|
|
|
|
typedef struct _JAVA_DIGEST_PARA
|
|
{
|
|
BOOL fDisableDigest;
|
|
PFN_SHP_DIGEST_DATA pfnDigestData;
|
|
HSHPDIGESTDATA hDigestData;
|
|
} JAVA_DIGEST_PARA, *PJAVA_DIGEST_PARA;
|
|
|
|
typedef struct _JAVA_SIGN_PARA
|
|
{
|
|
WORD wConstPoolCount;
|
|
WORD wSignConstPoolIndex;
|
|
LONG lSignConstPoolOffset;
|
|
WORD wAttrCount;
|
|
LONG lAttrCountOffset;
|
|
WORD wSignAttrIndex;
|
|
DWORD dwSignAttrLength;
|
|
LONG lSignAttrOffset;
|
|
LONG lEndOfFileOffset;
|
|
} JAVA_SIGN_PARA, *PJAVA_SIGN_PARA;
|
|
|
|
typedef struct _JAVA_READ_PARA
|
|
{
|
|
BOOL fResult;
|
|
DWORD dwLastError;
|
|
LONG lFileOffset;
|
|
DWORD cbCacheRead;
|
|
DWORD cbCacheRemain;
|
|
} JAVA_READ_PARA, *PJAVA_READ_PARA;
|
|
|
|
#define JAVA_READ_CACHE_LEN 512
|
|
|
|
typedef struct _JAVA_PARA
|
|
{
|
|
JAVA_FUNC_PARA Func;
|
|
JAVA_DIGEST_PARA Digest;
|
|
JAVA_SIGN_PARA Sign;
|
|
JAVA_READ_PARA Read;
|
|
BYTE rgbCache[JAVA_READ_CACHE_LEN];
|
|
} JAVA_PARA, *PJAVA_PARA;
|
|
|
|
|
|
|
|
#define JAVA_MAGIC 0xCAFEBABE
|
|
#define JAVA_MINOR_VERSION 3
|
|
#define JAVA_MAJOR_VERSION 45
|
|
|
|
// Constant Pool tags
|
|
//
|
|
// Note: CONSTANT_Long and CONSTANT_Double use two constant pool indexes.
|
|
enum
|
|
{
|
|
CONSTANT_Utf8 = 1,
|
|
CONSTANT_Unicode = 2,
|
|
CONSTANT_Integer = 3,
|
|
CONSTANT_Float = 4,
|
|
CONSTANT_Long = 5,
|
|
CONSTANT_Double = 6,
|
|
CONSTANT_Class = 7,
|
|
CONSTANT_String = 8,
|
|
CONSTANT_Fieldref = 9,
|
|
CONSTANT_Methodref = 10,
|
|
CONSTANT_InterfaceMethodref = 11,
|
|
CONSTANT_NameAndType = 12
|
|
};
|
|
|
|
// Constant Pool Info lengths (excludes the tag)
|
|
DWORD rgConstPoolLength[] =
|
|
{
|
|
0, // tag of zero not used
|
|
0, // CONSTANT_Utf8 (special case)
|
|
0, // CONSTANT_Unicode (special case)
|
|
4, // CONSTANT_Integer_info
|
|
4, // CONSTANT_Float_info
|
|
8, // CONSTANT_Long_info
|
|
8, // CONSTANT_Double_info
|
|
2, // CONSTANT_Class_info
|
|
2, // CONSTANT_String_info
|
|
4, // CONSTANT_Fieldref_info
|
|
4, // CONSTANT_Methodref_info
|
|
4, // CONSTANT_InterfaceMethodref_info
|
|
4 // CONSTANT_NameAndType_info
|
|
};
|
|
|
|
static inline void *ShpAlloc(DWORD cbytes)
|
|
{
|
|
void *pvRet;
|
|
|
|
pvRet = (void *)new BYTE[cbytes];
|
|
|
|
if (!(pvRet))
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
return(pvRet);
|
|
}
|
|
|
|
static inline void ShpFree(void *pv)
|
|
{
|
|
if (pv)
|
|
{
|
|
delete pv;
|
|
}
|
|
}
|
|
|
|
// The following functions convert to/from Java bytes which are big endian
|
|
static inline void ToJavaU2(WORD w, BYTE rgb[])
|
|
{
|
|
rgb[0] = HIBYTE(w);
|
|
rgb[1] = LOBYTE(w);
|
|
}
|
|
static inline WORD FromJavaU2(BYTE rgb[])
|
|
{
|
|
return ((WORD)rgb[0]<<8) | ((WORD)rgb[1]<<0);
|
|
}
|
|
|
|
static inline void ToJavaU4(DWORD dw, BYTE rgb[])
|
|
{
|
|
rgb[0] = HIBYTE(HIWORD(dw));
|
|
rgb[1] = LOBYTE(HIWORD(dw));
|
|
rgb[2] = HIBYTE(LOWORD(dw));
|
|
rgb[3] = LOBYTE(LOWORD(dw));
|
|
}
|
|
static inline DWORD FromJavaU4(BYTE rgb[])
|
|
{
|
|
return ((DWORD)rgb[0]<<24) |
|
|
((DWORD)rgb[1]<<16) |
|
|
((DWORD)rgb[2]<<8) |
|
|
((DWORD)rgb[3]<<0);
|
|
}
|
|
|
|
#define CONST_POOL_COUNT_OFFSET 8
|
|
#define UTF8_HDR_LENGTH (1+2)
|
|
#define ATTR_HDR_LENGTH (2+4)
|
|
#define SIGN_ATTR_NAME_LENGTH 19
|
|
#define SIGN_CONST_POOL_LENGTH (UTF8_HDR_LENGTH + SIGN_ATTR_NAME_LENGTH)
|
|
|
|
static const char rgchSignAttrName[SIGN_ATTR_NAME_LENGTH + 1] =
|
|
"_digital_signature_";
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Shift the bytes in the file.
|
|
//
|
|
// If lbShift is positive, the bytes are shifted toward the end of the file.
|
|
// If lbShift is negative, the bytes are shifted toward the start of the file.
|
|
//--------------------------------------------------------------------------
|
|
static
|
|
BOOL
|
|
JavaShiftFileBytes(
|
|
IN HANDLE hFile,
|
|
IN PBYTE pbCache,
|
|
IN LONG cbCache,
|
|
IN LONG lStartOffset,
|
|
IN LONG lEndOffset,
|
|
IN LONG lbShift
|
|
)
|
|
{
|
|
LONG cbTotalMove, cbMove;
|
|
|
|
cbTotalMove = lEndOffset - lStartOffset;
|
|
while (cbTotalMove) {
|
|
cbMove = min(cbTotalMove, cbCache);
|
|
|
|
if (lbShift > 0) {
|
|
if (!SeekAndReadFile(hFile, lEndOffset - cbMove,
|
|
pbCache, cbMove))
|
|
return FALSE;
|
|
if (!SeekAndWriteFile(hFile, (lEndOffset - cbMove) + lbShift,
|
|
pbCache, cbMove))
|
|
return FALSE;
|
|
lEndOffset -= cbMove;
|
|
} else if (lbShift < 0) {
|
|
if (!SeekAndReadFile(hFile, lStartOffset, pbCache, cbMove))
|
|
return FALSE;
|
|
if (!SeekAndWriteFile(hFile, lStartOffset + lbShift,
|
|
pbCache, cbMove))
|
|
return FALSE;
|
|
lStartOffset += cbMove;
|
|
}
|
|
cbTotalMove -= cbMove;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Low level functions for reading the Java Class File.
|
|
//
|
|
// If not disabled, the read bytes are also hashed.
|
|
//
|
|
// For an error, remaining unread values are zero'ed and
|
|
// pPara->Read.fResult = FALSE.
|
|
//--------------------------------------------------------------------------
|
|
static void ReadJavaBytes(
|
|
IN PJAVA_PARA pPara,
|
|
OUT OPTIONAL BYTE *pb, // if NULL, bytes are hashed and then skipped
|
|
IN DWORD cb
|
|
)
|
|
{
|
|
DWORD cbCacheRemain = pPara->Read.cbCacheRemain;
|
|
DWORD lFileOffset = pPara->Read.lFileOffset;
|
|
BOOL fDisableDigest = pPara->Digest.pfnDigestData == NULL ||
|
|
pPara->Digest.fDisableDigest;
|
|
|
|
if (!pPara->Read.fResult)
|
|
goto ErrorReturn;
|
|
|
|
while (cb > 0) {
|
|
DWORD cbCopy;
|
|
BYTE *pbCache;
|
|
|
|
if (cbCacheRemain == 0) {
|
|
if (!ReadFile(pPara->Func.hFile, pPara->rgbCache,
|
|
sizeof(pPara->rgbCache), &cbCacheRemain, NULL))
|
|
goto ErrorReturn;
|
|
if (cbCacheRemain == 0) goto ErrorReturn;
|
|
pPara->Read.cbCacheRead = cbCacheRemain;
|
|
}
|
|
|
|
cbCopy = min(cb, cbCacheRemain);
|
|
pbCache = &pPara->rgbCache[pPara->Read.cbCacheRead - cbCacheRemain];
|
|
if (!fDisableDigest) {
|
|
if (!pPara->Digest.pfnDigestData(
|
|
pPara->Digest.hDigestData,
|
|
pbCache,
|
|
cbCopy)) goto ErrorReturn;
|
|
}
|
|
if (pb) {
|
|
memcpy(pb, pbCache, cbCopy);
|
|
pb += cbCopy;
|
|
}
|
|
cb -= cbCopy;
|
|
cbCacheRemain -= cbCopy;
|
|
lFileOffset += cbCopy;
|
|
}
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
if (pPara->Read.fResult) {
|
|
// First error
|
|
pPara->Read.fResult = FALSE;
|
|
pPara->Read.dwLastError = GetLastError();
|
|
}
|
|
if (pb && cb)
|
|
memset(pb, 0, cb);
|
|
CommonReturn:
|
|
pPara->Read.cbCacheRemain = cbCacheRemain;
|
|
pPara->Read.lFileOffset = lFileOffset;
|
|
|
|
}
|
|
|
|
static void SkipJavaBytes(IN PJAVA_PARA pPara, IN DWORD cb)
|
|
{
|
|
ReadJavaBytes(pPara, NULL, cb);
|
|
}
|
|
|
|
static BYTE ReadJavaU1(IN PJAVA_PARA pPara)
|
|
{
|
|
BYTE b;
|
|
ReadJavaBytes(pPara, &b, 1);
|
|
return b;
|
|
}
|
|
static WORD ReadJavaU2(IN PJAVA_PARA pPara)
|
|
{
|
|
BYTE rgb[2];
|
|
ReadJavaBytes(pPara, rgb, 2);
|
|
return FromJavaU2(rgb);
|
|
}
|
|
static DWORD ReadJavaU4(IN PJAVA_PARA pPara)
|
|
{
|
|
BYTE rgb[4];
|
|
ReadJavaBytes(pPara, rgb, 4);
|
|
return FromJavaU4(rgb);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// .
|
|
//--------------------------------------------------------------------------
|
|
static
|
|
BOOL
|
|
GetSignedDataFromJavaClassFile(
|
|
IN HSHPSIGNFILE hSignFile,
|
|
OUT BYTE **ppbSignedData,
|
|
OUT DWORD *pcbSignedData
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
PJAVA_PARA pPara = (PJAVA_PARA) hSignFile;
|
|
BYTE *pbSignedData = NULL;
|
|
DWORD cbSignedData;
|
|
|
|
cbSignedData = pPara->Sign.dwSignAttrLength;
|
|
if (cbSignedData == 0) {
|
|
SetLastError((DWORD)TRUST_E_NOSIGNATURE);
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
pbSignedData = pPara->Func.pbSignedData;
|
|
if (pbSignedData == NULL) {
|
|
if (NULL == (pbSignedData = (BYTE *) ShpAlloc(cbSignedData)))
|
|
goto ErrorReturn;
|
|
if (!SeekAndReadFile(
|
|
pPara->Func.hFile,
|
|
pPara->Sign.lSignAttrOffset + ATTR_HDR_LENGTH,
|
|
pbSignedData,
|
|
cbSignedData))
|
|
goto ErrorReturn;
|
|
pPara->Func.pbSignedData = pbSignedData;
|
|
}
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
if (pbSignedData) {
|
|
ShpFree(pbSignedData);
|
|
pbSignedData = NULL;
|
|
}
|
|
cbSignedData = 0;
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
*ppbSignedData = pbSignedData;
|
|
*pcbSignedData = cbSignedData;
|
|
return fResult;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// .
|
|
//--------------------------------------------------------------------------
|
|
static
|
|
BOOL
|
|
SetSignedDataIntoJavaClassFile(
|
|
IN HSHPSIGNFILE hSignFile,
|
|
IN const BYTE *pbSignedData,
|
|
IN DWORD cbSignedData
|
|
)
|
|
{
|
|
PJAVA_PARA pPara = (PJAVA_PARA) hSignFile;
|
|
HANDLE hFile = pPara->Func.hFile;
|
|
|
|
if (pbSignedData == NULL || cbSignedData == 0)
|
|
// Length only
|
|
return TRUE;
|
|
|
|
if (pPara->Sign.wSignConstPoolIndex == pPara->Sign.wConstPoolCount) {
|
|
BYTE rgb[SIGN_CONST_POOL_LENGTH];
|
|
// Add a new constant pool entry for the name of the
|
|
// signed data attribute.
|
|
|
|
// First, make room in the file by shifting all the bytes that follow.
|
|
if (!JavaShiftFileBytes(
|
|
pPara->Func.hFile,
|
|
pPara->rgbCache,
|
|
sizeof(pPara->rgbCache),
|
|
pPara->Sign.lSignConstPoolOffset,
|
|
pPara->Sign.lEndOfFileOffset,
|
|
SIGN_CONST_POOL_LENGTH))
|
|
return FALSE;
|
|
|
|
// Update offsets that have been shifted
|
|
pPara->Sign.lAttrCountOffset += SIGN_CONST_POOL_LENGTH;
|
|
pPara->Sign.lSignAttrOffset += SIGN_CONST_POOL_LENGTH;
|
|
pPara->Sign.lEndOfFileOffset += SIGN_CONST_POOL_LENGTH;
|
|
|
|
// Increment u2 constant_pool_count and update in file
|
|
pPara->Sign.wConstPoolCount++;
|
|
ToJavaU2(pPara->Sign.wConstPoolCount, rgb);
|
|
if (!SeekAndWriteFile(hFile, CONST_POOL_COUNT_OFFSET, rgb, 2))
|
|
return FALSE;
|
|
|
|
// Add constant pool entry for the sign attr name and update in file
|
|
rgb[0] = CONSTANT_Utf8;
|
|
ToJavaU2(SIGN_ATTR_NAME_LENGTH, &rgb[1]);
|
|
memcpy(&rgb[1+2], rgchSignAttrName, SIGN_ATTR_NAME_LENGTH);
|
|
if (!SeekAndWriteFile(hFile, pPara->Sign.lSignConstPoolOffset, rgb,
|
|
SIGN_CONST_POOL_LENGTH))
|
|
return FALSE;
|
|
}
|
|
|
|
if (pPara->Sign.dwSignAttrLength == 0) {
|
|
// Add a new attribute for the signed data. The attribute will
|
|
// be added at the end of the file.
|
|
assert(pPara->Sign.lSignAttrOffset == pPara->Sign.lEndOfFileOffset);
|
|
pPara->Sign.lEndOfFileOffset += ATTR_HDR_LENGTH + cbSignedData;
|
|
|
|
// Increment u2 attribute_count and update in file
|
|
BYTE rgb[2];
|
|
pPara->Sign.wAttrCount++;
|
|
ToJavaU2(pPara->Sign.wAttrCount, rgb);
|
|
if (!SeekAndWriteFile(hFile, pPara->Sign.lAttrCountOffset, rgb, 2))
|
|
return FALSE;
|
|
|
|
} else {
|
|
// The file already has a signed data attribute.
|
|
|
|
// If its length is different from the new signed data
|
|
// then, the bytes that follow the attribute will
|
|
// need to be shifted by the difference in length of the old and new
|
|
// signed data
|
|
LONG lbShift = cbSignedData - pPara->Sign.dwSignAttrLength;
|
|
if (lbShift != 0) {
|
|
if (!JavaShiftFileBytes(
|
|
pPara->Func.hFile,
|
|
pPara->rgbCache,
|
|
sizeof(pPara->rgbCache),
|
|
pPara->Sign.lSignAttrOffset +
|
|
(ATTR_HDR_LENGTH + pPara->Sign.dwSignAttrLength),
|
|
pPara->Sign.lEndOfFileOffset,
|
|
lbShift))
|
|
return FALSE;
|
|
|
|
pPara->Sign.lEndOfFileOffset += lbShift;
|
|
}
|
|
}
|
|
pPara->Sign.dwSignAttrLength = cbSignedData;
|
|
|
|
{
|
|
// Update the file with the signed data attribute
|
|
BYTE rgb[ATTR_HDR_LENGTH];
|
|
DWORD cbWritten;
|
|
ToJavaU2(pPara->Sign.wSignConstPoolIndex, rgb); // u2 attribute_name
|
|
ToJavaU4(cbSignedData, &rgb[2]); // u4 attribute_length
|
|
if (!SeekAndWriteFile(hFile, pPara->Sign.lSignAttrOffset, rgb,
|
|
ATTR_HDR_LENGTH))
|
|
return FALSE;
|
|
if (!WriteFile(hFile, pbSignedData, cbSignedData, &cbWritten, NULL) ||
|
|
cbWritten != cbSignedData)
|
|
return FALSE;
|
|
}
|
|
|
|
// Set end of file
|
|
if (0xFFFFFFFF == SetFilePointer(
|
|
hFile,
|
|
pPara->Sign.lEndOfFileOffset,
|
|
NULL, // lpDistanceToMoveHigh
|
|
FILE_BEGIN))
|
|
return FALSE;
|
|
return SetEndOfFile(hFile);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Reads and optionally digests the Java Class file. Locates the signed data.
|
|
//--------------------------------------------------------------------------
|
|
static
|
|
BOOL
|
|
ProcessJavaClassFile(
|
|
PJAVA_PARA pPara,
|
|
BOOL fInit
|
|
)
|
|
{
|
|
char rgchTmpSignAttrName[SIGN_ATTR_NAME_LENGTH];
|
|
WORD wLength;
|
|
DWORD dwLength;
|
|
WORD wCount;
|
|
WORD wConstPoolCount;
|
|
WORD wConstPoolIndex;
|
|
WORD wSignConstPoolIndex;
|
|
WORD wAttrCount;
|
|
WORD wAttrIndex;
|
|
WORD wAttrName;
|
|
WORD wSignAttrIndex;
|
|
LONG lAddConstPoolOffset;
|
|
int i;
|
|
|
|
memset(&pPara->Read, 0, sizeof(pPara->Read));
|
|
pPara->Read.fResult = TRUE;
|
|
if (0xFFFFFFFF == SetFilePointer(
|
|
pPara->Func.hFile,
|
|
0, // lDistanceToMove
|
|
NULL, // lpDistanceToMoveHigh
|
|
FILE_BEGIN))
|
|
return FALSE;
|
|
if (fInit) {
|
|
memset(&pPara->Digest, 0, sizeof(pPara->Digest));
|
|
memset(&pPara->Sign, 0, sizeof(pPara->Sign));
|
|
}
|
|
|
|
// Default is to be digested. We'll disable where appropriate. Note,
|
|
// skipped bytes are still digested.
|
|
pPara->Digest.fDisableDigest = FALSE;
|
|
|
|
// Read / skip the fields at the beginning of the class file
|
|
if (ReadJavaU4(pPara) != JAVA_MAGIC)
|
|
{ // u4 magic
|
|
SetLastError(ERROR_BAD_FORMAT);
|
|
return FALSE;
|
|
}
|
|
SkipJavaBytes(pPara, 2 + 2); // u2 minor_version
|
|
// u2 major_version
|
|
|
|
pPara->Digest.fDisableDigest = TRUE;
|
|
wConstPoolCount = ReadJavaU2(pPara); // u2 constant_pool_count
|
|
pPara->Digest.fDisableDigest = FALSE;
|
|
|
|
// For fInit, wSignConstPoolIndex has already been zeroed
|
|
wSignConstPoolIndex = pPara->Sign.wSignConstPoolIndex;
|
|
|
|
// Iterate through the constant pools. Don't digest the constant pool
|
|
// containing the _digital_signature_ name (wSignConstPoolIndex).
|
|
// For fInit, find the last "_digital_signature_".
|
|
//
|
|
// Note: constant pool index 0 isn't stored in the file.
|
|
wConstPoolIndex = 1;
|
|
while (wConstPoolIndex < wConstPoolCount) {
|
|
BYTE bTag;
|
|
|
|
if (wConstPoolIndex == wSignConstPoolIndex)
|
|
pPara->Digest.fDisableDigest = TRUE;
|
|
|
|
bTag = ReadJavaU1(pPara);
|
|
switch (bTag) {
|
|
case CONSTANT_Utf8:
|
|
wLength = ReadJavaU2(pPara);
|
|
if (fInit && wLength == SIGN_ATTR_NAME_LENGTH) {
|
|
ReadJavaBytes(pPara, (BYTE *) rgchTmpSignAttrName,
|
|
SIGN_ATTR_NAME_LENGTH);
|
|
if (memcmp(rgchSignAttrName, rgchTmpSignAttrName,
|
|
SIGN_ATTR_NAME_LENGTH) == 0) {
|
|
wSignConstPoolIndex = wConstPoolIndex;
|
|
pPara->Sign.lSignConstPoolOffset =
|
|
pPara->Read.lFileOffset - SIGN_CONST_POOL_LENGTH;
|
|
|
|
}
|
|
} else
|
|
SkipJavaBytes(pPara, wLength);
|
|
break;
|
|
case CONSTANT_Unicode:
|
|
wLength = ReadJavaU2(pPara);
|
|
SkipJavaBytes(pPara, ((DWORD) wLength) * 2);
|
|
break;
|
|
case CONSTANT_Integer:
|
|
case CONSTANT_Float:
|
|
case CONSTANT_Long:
|
|
case CONSTANT_Double:
|
|
case CONSTANT_Class:
|
|
case CONSTANT_String:
|
|
case CONSTANT_Fieldref:
|
|
case CONSTANT_Methodref:
|
|
case CONSTANT_InterfaceMethodref:
|
|
case CONSTANT_NameAndType:
|
|
SkipJavaBytes(pPara, rgConstPoolLength[bTag]);
|
|
break;
|
|
default:
|
|
SetLastError(ERROR_BAD_FORMAT);
|
|
return FALSE;
|
|
}
|
|
|
|
pPara->Digest.fDisableDigest = FALSE;
|
|
|
|
if (bTag == CONSTANT_Long || bTag == CONSTANT_Double)
|
|
wConstPoolIndex += 2;
|
|
else
|
|
wConstPoolIndex++;
|
|
}
|
|
|
|
if (fInit) {
|
|
lAddConstPoolOffset = pPara->Read.lFileOffset;
|
|
if (wSignConstPoolIndex == 0) {
|
|
// Didn't find a constant pool for the digital_signature. Update
|
|
// with where it will need to be added
|
|
wSignConstPoolIndex = wConstPoolCount;
|
|
pPara->Sign.lSignConstPoolOffset = lAddConstPoolOffset;
|
|
}
|
|
}
|
|
|
|
// Globble up and hash the bytes until we reach the attributes which are
|
|
// at the end of the file.
|
|
|
|
SkipJavaBytes(pPara, 2 + 2 + 2); // u2 access_flags
|
|
// u2 this_class
|
|
// u2 super_class
|
|
wCount = ReadJavaU2(pPara); // u2 interfaces_count
|
|
// u2 interfaces[interfaces_count]
|
|
SkipJavaBytes(pPara, ((DWORD) wCount) * 2);
|
|
|
|
// Since fields and methods have identical class file storage, do this
|
|
// twice.
|
|
i = 2;
|
|
while (i--) {
|
|
wCount = ReadJavaU2(pPara); // u2 fields_count | methods_count
|
|
while (wCount--) {
|
|
SkipJavaBytes(pPara, 2 + 2 + 2); // u2 access_flags
|
|
// u2 name_index
|
|
// u2 signature_index
|
|
wAttrCount = ReadJavaU2(pPara); // u2 attributes_count
|
|
while (wAttrCount--) {
|
|
SkipJavaBytes(pPara, 2); // u2 attribute_name
|
|
dwLength = ReadJavaU4(pPara); // u4 attribute_length
|
|
SkipJavaBytes(pPara, dwLength); // u1 info[attribute_length]
|
|
}
|
|
}
|
|
}
|
|
|
|
// Finally, the attributes. This is where the signed data is
|
|
|
|
pPara->Sign.lAttrCountOffset = pPara->Read.lFileOffset;
|
|
pPara->Digest.fDisableDigest = TRUE;
|
|
wAttrCount = ReadJavaU2(pPara); // u2 attributes_count
|
|
pPara->Digest.fDisableDigest = FALSE;
|
|
|
|
if (fInit) {
|
|
pPara->Sign.wAttrCount = wAttrCount;
|
|
wSignAttrIndex = 0xFFFF;
|
|
} else
|
|
wSignAttrIndex = pPara->Sign.wSignAttrIndex;
|
|
|
|
for (wAttrIndex = 0; wAttrIndex < wAttrCount; wAttrIndex++) {
|
|
if (wAttrIndex == wSignAttrIndex)
|
|
pPara->Digest.fDisableDigest = TRUE;
|
|
|
|
wAttrName = ReadJavaU2(pPara);
|
|
dwLength = ReadJavaU4(pPara); // u4 attribute_length
|
|
SkipJavaBytes(pPara, dwLength); // u1 info[attribute_length]
|
|
if (fInit && wAttrName == wSignConstPoolIndex && dwLength > 0 &&
|
|
wSignConstPoolIndex < wConstPoolCount) {
|
|
wSignAttrIndex = wAttrIndex;
|
|
pPara->Sign.lSignAttrOffset =
|
|
pPara->Read.lFileOffset - (ATTR_HDR_LENGTH + dwLength);
|
|
pPara->Sign.dwSignAttrLength = dwLength;
|
|
}
|
|
|
|
pPara->Digest.fDisableDigest = FALSE;
|
|
}
|
|
|
|
if (fInit) {
|
|
if (wSignAttrIndex == 0xFFFF) {
|
|
// Didn't find an attribute for the digital_signature. Update
|
|
// with where it will need to be added
|
|
wSignAttrIndex = wAttrCount;
|
|
pPara->Sign.lSignAttrOffset = pPara->Read.lFileOffset;
|
|
|
|
// Also, force us to use a new const pool for the name of the
|
|
// attribute
|
|
wSignConstPoolIndex = wConstPoolCount;
|
|
pPara->Sign.lSignConstPoolOffset = lAddConstPoolOffset;
|
|
}
|
|
|
|
pPara->Sign.wSignConstPoolIndex = wSignConstPoolIndex;
|
|
pPara->Sign.wConstPoolCount = wConstPoolCount;
|
|
pPara->Sign.wSignAttrIndex = wSignAttrIndex;
|
|
pPara->Sign.lEndOfFileOffset = pPara->Read.lFileOffset;
|
|
}
|
|
|
|
// Now check if we got any hash or file errors while processing the file
|
|
return pPara->Read.fResult;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Digest the appropriate bytes from a java file, for a digital signature.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
JavaGetDigestStream(
|
|
IN HANDLE FileHandle,
|
|
IN DWORD DigestLevel,
|
|
IN DIGEST_FUNCTION DigestFunction,
|
|
IN DIGEST_HANDLE DigestHandle
|
|
)
|
|
{
|
|
BOOL fRet;
|
|
JAVA_PARA Para;
|
|
memset( &Para.Func, 0, sizeof(Para.Func));
|
|
|
|
assert( DigestLevel == 0);
|
|
Para.Func.hFile = FileHandle;
|
|
if (!ProcessJavaClassFile( &Para, TRUE))
|
|
goto ProcessJavaClassFileTrueError;
|
|
|
|
Para.Digest.pfnDigestData = DigestFunction;
|
|
Para.Digest.hDigestData = DigestHandle;
|
|
|
|
if (!ProcessJavaClassFile( &Para, FALSE))
|
|
goto ProcessJavaClassFileFalseError;
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
if (Para.Func.pbSignedData)
|
|
ShpFree( Para.Func.pbSignedData);
|
|
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
TRACE_ERROR_EX(DBG_SS,ProcessJavaClassFileTrueError)
|
|
TRACE_ERROR_EX(DBG_SS,ProcessJavaClassFileFalseError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Add a digital signature to a java file.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
JavaAddCertificate(
|
|
IN HANDLE FileHandle,
|
|
IN LPWIN_CERTIFICATE Certificate,
|
|
OUT PDWORD Index
|
|
)
|
|
{
|
|
BOOL fRet;
|
|
JAVA_PARA Para;
|
|
memset( &Para.Func, 0, sizeof(Para.Func));
|
|
|
|
Para.Func.hFile = FileHandle;
|
|
if (!ProcessJavaClassFile( &Para, TRUE))
|
|
goto ProcessJavaClassFileTrueError;
|
|
|
|
if (!SetSignedDataIntoJavaClassFile(
|
|
(HSHPSIGNFILE)&Para,
|
|
(PBYTE)&(Certificate->bCertificate),
|
|
Certificate->dwLength - OFFSETOF(WIN_CERTIFICATE,bCertificate)))
|
|
goto SetSignedDataIntoJavaClassFileError;
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
if (Para.Func.pbSignedData)
|
|
ShpFree( Para.Func.pbSignedData);
|
|
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
TRACE_ERROR_EX(DBG_SS,ProcessJavaClassFileTrueError)
|
|
TRACE_ERROR_EX(DBG_SS,SetSignedDataIntoJavaClassFileError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Remove a digital signature from a java file.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
JavaRemoveCertificate(
|
|
IN HANDLE FileHandle,
|
|
IN DWORD Index
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Enum the digital signatures in a java file.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
JavaEnumerateCertificates(
|
|
IN HANDLE FileHandle,
|
|
IN WORD TypeFilter,
|
|
OUT PDWORD CertificateCount,
|
|
IN OUT PDWORD Indices OPTIONAL,
|
|
IN OUT DWORD IndexCount OPTIONAL
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Get a digital signature from a java file.
|
|
//--------------------------------------------------------------------------
|
|
static
|
|
BOOL
|
|
I_JavaGetCertificate(
|
|
IN HANDLE FileHandle,
|
|
IN DWORD CertificateIndex,
|
|
OUT LPWIN_CERTIFICATE Certificate,
|
|
IN OUT OPTIONAL PDWORD RequiredLength
|
|
)
|
|
{
|
|
BOOL fRet;
|
|
JAVA_PARA Para;
|
|
memset( &Para.Func, 0, sizeof(Para.Func));
|
|
BYTE *pbSignedData = NULL;
|
|
DWORD cbSignedData;
|
|
DWORD cbCert;
|
|
DWORD dwError;
|
|
|
|
if (CertificateIndex != 0)
|
|
goto IndexNonZeroError;
|
|
|
|
Para.Func.hFile = FileHandle;
|
|
if (!ProcessJavaClassFile( &Para, TRUE))
|
|
goto ProcessJavaClassFileTrueError;
|
|
|
|
if (!GetSignedDataFromJavaClassFile(
|
|
(HSHPSIGNFILE)&Para,
|
|
&pbSignedData,
|
|
&cbSignedData))
|
|
goto GetSignedDataFromJavaClassFileError;
|
|
|
|
cbCert = OFFSETOF(WIN_CERTIFICATE,bCertificate) + cbSignedData;
|
|
dwError = 0;
|
|
__try {
|
|
if (RequiredLength) {
|
|
// RequiredLength non-NULL only if getting cert data
|
|
if (*RequiredLength < cbCert) {
|
|
*RequiredLength = cbCert;
|
|
dwError = ERROR_INSUFFICIENT_BUFFER;
|
|
} else {
|
|
memcpy( Certificate->bCertificate, pbSignedData, cbSignedData);
|
|
}
|
|
}
|
|
if (dwError == 0) {
|
|
Certificate->dwLength = cbCert;
|
|
Certificate->wRevision = WIN_CERT_REVISION_1_0;
|
|
Certificate->wCertificateType = WIN_CERT_TYPE_PKCS_SIGNED_DATA;
|
|
}
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (dwError) {
|
|
SetLastError( dwError);
|
|
fRet = FALSE;
|
|
} else {
|
|
fRet = TRUE;
|
|
}
|
|
CommonReturn:
|
|
ShpFree( Para.Func.pbSignedData);
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
TRACE_ERROR_EX(DBG_SS,IndexNonZeroError)
|
|
TRACE_ERROR_EX(DBG_SS,ProcessJavaClassFileTrueError)
|
|
TRACE_ERROR_EX(DBG_SS,GetSignedDataFromJavaClassFileError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Get a digital signature from a java file.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
JavaGetCertificateData(
|
|
IN HANDLE FileHandle,
|
|
IN DWORD CertificateIndex,
|
|
OUT LPWIN_CERTIFICATE Certificate,
|
|
IN OUT PDWORD RequiredLength
|
|
)
|
|
{
|
|
BOOL fRet;
|
|
|
|
if (RequiredLength == NULL)
|
|
goto RequiredLengthNullError;
|
|
|
|
fRet = I_JavaGetCertificate(
|
|
FileHandle,
|
|
CertificateIndex,
|
|
Certificate,
|
|
RequiredLength
|
|
);
|
|
|
|
CommonReturn:
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
SET_ERROR(RequiredLengthNullError, ERROR_INVALID_PARAMETER)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Get the header of a digital signature from a java file.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
JavaGetCertificateHeader(
|
|
IN HANDLE FileHandle,
|
|
IN DWORD CertificateIndex,
|
|
IN OUT LPWIN_CERTIFICATE Certificateheader
|
|
)
|
|
{
|
|
return I_JavaGetCertificate(
|
|
FileHandle,
|
|
CertificateIndex,
|
|
Certificateheader,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Seeks and writes bytes to file
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
SeekAndWriteFile(
|
|
IN HANDLE hFile,
|
|
IN DWORD lFileOffset,
|
|
IN BYTE *pb,
|
|
IN DWORD cb
|
|
)
|
|
{
|
|
DWORD cbWritten;
|
|
|
|
if (0xFFFFFFFF == SetFilePointer(
|
|
hFile,
|
|
lFileOffset,
|
|
NULL, // lpDistanceToMoveHigh
|
|
FILE_BEGIN))
|
|
return FALSE;
|
|
if (!WriteFile(hFile, pb, cb, &cbWritten, NULL) || cbWritten != cb)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Seeks and reads bytes from file
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
SeekAndReadFile(
|
|
IN HANDLE hFile,
|
|
IN DWORD lFileOffset,
|
|
OUT BYTE *pb,
|
|
IN DWORD cb
|
|
)
|
|
{
|
|
DWORD cbRead;
|
|
|
|
if (0xFFFFFFFF == SetFilePointer(
|
|
hFile,
|
|
lFileOffset,
|
|
NULL, // lpDistanceToMoveHigh
|
|
FILE_BEGIN))
|
|
return FALSE;
|
|
if (!ReadFile(hFile, pb, cb, &cbRead, NULL) || cbRead != cb)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|