Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'mcs/class/Mono.Security/Mono.Security.Authenticode/AuthenticodeBase.cs')
-rwxr-xr-xmcs/class/Mono.Security/Mono.Security.Authenticode/AuthenticodeBase.cs184
1 files changed, 143 insertions, 41 deletions
diff --git a/mcs/class/Mono.Security/Mono.Security.Authenticode/AuthenticodeBase.cs b/mcs/class/Mono.Security/Mono.Security.Authenticode/AuthenticodeBase.cs
index 63fbab93a8c..c2d609ecec2 100755
--- a/mcs/class/Mono.Security/Mono.Security.Authenticode/AuthenticodeBase.cs
+++ b/mcs/class/Mono.Security/Mono.Security.Authenticode/AuthenticodeBase.cs
@@ -5,9 +5,7 @@
// Sebastien Pouliot <sebastien@ximian.com>
//
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// (C) 2004 Novell (http://www.novell.com)
-//
-
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -58,63 +56,167 @@ namespace Mono.Security.Authenticode {
public const string spcIndirectDataContext = "1.3.6.1.4.1.311.2.1.4";
- internal byte[] rawData;
+ private byte[] fileblock;
+ private FileStream fs;
+ private int blockNo;
+ private int blockLength;
+ private int peOffset;
+ private int dirSecurityOffset;
+ private int dirSecuritySize;
public AuthenticodeBase ()
{
+ fileblock = new byte [4096];
}
- protected byte[] HashFile (string fileName, string hashName)
+ internal void Open (string filename)
{
- FileStream fs = new FileStream (fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
- byte[] file = new byte [fs.Length];
- fs.Read (file, 0, file.Length);
- fs.Close ();
+ if (fs != null)
+ Close ();
+ fs = new FileStream (filename, FileMode.Open, FileAccess.Read, FileShare.Read);
+ }
- // MZ - DOS header
- if (BitConverterLE.ToUInt16 (file, 0) != 0x5A4D)
- return null;
+ internal void Close ()
+ {
+ if (fs != null) {
+ fs.Close ();
+ fs = null;
+ blockNo = 0;
+ }
+ }
- // find offset of PE header
- int peOffset = BitConverterLE.ToInt32 (file, 60);
- if (peOffset > file.Length)
- return null;
+ internal bool ReadFirstBlock ()
+ {
+ if (fs == null)
+ return false;
+
+ fs.Position = 0;
+ // read first block - it will include (100% sure)
+ // the MZ header and (99.9% sure) the PE header
+ blockLength = fs.Read (fileblock, 0, fileblock.Length);
+ blockNo = 1;
+ if (blockLength < 64)
+ return false; // invalid PE file
+
+ // 1. Validate the MZ header informations
+ // 1.1. Check for magic MZ at start of header
+ if (BitConverterLE.ToUInt16 (fileblock, 0) != 0x5A4D)
+ return false;
+
+ // 1.2. Find the offset of the PE header
+ peOffset = BitConverterLE.ToInt32 (fileblock, 60);
+ if (peOffset > fileblock.Length) {
+ // just in case (0.1%) this can actually happen
+ string msg = String.Format (Locale.GetText (
+ "Header size too big (> {0} bytes)."),
+ fileblock.Length);
+ throw new NotSupportedException (msg);
+ }
+ if (peOffset > fs.Length)
+ return false;
- // PE - NT header
- if (BitConverterLE.ToUInt16 (file, peOffset) != 0x4550)
- return null;
+ // 2. Read between DOS header and first part of PE header
+ // 2.1. Check for magic PE at start of header
+ if (BitConverterLE.ToUInt16 (fileblock, peOffset) != 0x4550)
+ return false;
- // IMAGE_DIRECTORY_ENTRY_SECURITY
- int dirSecurityOffset = BitConverterLE.ToInt32 (file, peOffset + 152);
- int dirSecuritySize = BitConverterLE.ToInt32 (file, peOffset + 156);
+ // 2.2. Locate IMAGE_DIRECTORY_ENTRY_SECURITY (offset and size)
+ dirSecurityOffset = BitConverterLE.ToInt32 (fileblock, peOffset + 152);
+ dirSecuritySize = BitConverterLE.ToInt32 (fileblock, peOffset + 156);
+
+ return true;
+ }
+
+ internal byte[] GetSecurityEntry ()
+ {
+ if (blockNo < 1)
+ ReadFirstBlock ();
if (dirSecuritySize > 8) {
- rawData = new byte [dirSecuritySize - 8];
- Buffer.BlockCopy (file, dirSecurityOffset + 8, rawData, 0, rawData.Length);
-/* DEBUG
- FileStream debug = new FileStream (fileName + ".sig", FileMode.Create, FileAccess.Write);
- debug.Write (rawData, 0, rawData.Length);
- debug.Close ();*/
+ // remove header from size (not ASN.1 based)
+ byte[] secEntry = new byte [dirSecuritySize - 8];
+ // position after header and read entry
+ fs.Position = dirSecurityOffset + 8;
+ fs.Read (secEntry, 0, secEntry.Length);
+ return secEntry;
+ }
+ return null;
+ }
+
+ // returns null if the file isn't signed
+ internal byte[] GetHash (HashAlgorithm hash)
+ {
+ if (blockNo < 1)
+ ReadFirstBlock ();
+ fs.Position = blockLength;
+
+ // hash the rest of the file
+ long n = fs.Length - blockLength;
+ // minus any authenticode signature (with 8 bytes header)
+ if (dirSecurityOffset > 0) {
+ // it is also possible that the signature block
+ // starts within the block in memory (small EXE)
+ if (dirSecurityOffset < blockLength) {
+ blockLength = dirSecurityOffset;
+ n = 0;
+ }
+ else
+ n -= (dirSecuritySize);
}
- else
- rawData = null;
- HashAlgorithm hash = HashAlgorithm.Create (hashName);
- // 0 to 215 (216) then skip 4 (checksum)
+ // Authenticode(r) gymnastics
+ // Hash from (generally) 0 to 215 (216 bytes)
int pe = peOffset + 88;
- hash.TransformBlock (file, 0, pe, file, 0);
+ hash.TransformBlock (fileblock, 0, pe, fileblock, 0);
+ // then skip 4 for checksum
pe += 4;
- // 220 to 279 (60) then skip 8 (IMAGE_DIRECTORY_ENTRY_SECURITY)
- hash.TransformBlock (file, pe, 60, file, pe);
+ // Continue hashing from (generally) 220 to 279 (60 bytes)
+ hash.TransformBlock (fileblock, pe, 60, fileblock, pe);
+ // then skip 8 bytes for IMAGE_DIRECTORY_ENTRY_SECURITY
pe += 68;
- // 288 to end of file
- int n = file.Length - pe;
- // minus any authenticode signature (with 8 bytes header)
- if (dirSecurityOffset != 0)
- n -= (dirSecuritySize);
- hash.TransformFinalBlock (file, pe, n);
+ // everything is present so start the hashing
+ if (n == 0) {
+ // hash the (only) block
+ hash.TransformFinalBlock (fileblock, pe, blockLength - pe);
+ }
+ else {
+ // hash the last part of the first (already in memory) block
+ hash.TransformBlock (fileblock, pe, blockLength - pe, fileblock, 0);
+
+ // hash by blocks of 4096 bytes
+ long blocks = (n >> 12);
+ int remainder = (int)(n - (blocks << 12));
+ if (remainder == 0) {
+ blocks--;
+ remainder = 4096;
+ }
+ // blocks
+ while (blocks-- > 0) {
+ fs.Read (fileblock, 0, fileblock.Length);
+ hash.TransformBlock (fileblock, 0, fileblock.Length, fileblock, 0);
+ }
+ // remainder
+ if (fs.Read (fileblock, 0, remainder) != remainder)
+ return null;
+ hash.TransformFinalBlock (fileblock, 0, remainder);
+ }
return hash.Hash;
}
+
+ // for compatibility only
+ protected byte[] HashFile (string fileName, string hashName)
+ {
+ try {
+ Open (fileName);
+ HashAlgorithm hash = HashAlgorithm.Create (hashName);
+ byte[] result = GetHash (hash);
+ Close ();
+ return result;
+ }
+ catch {
+ return null;
+ }
+ }
}
}