//+------------------------------------------------------------------------- // // 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; }