Author: spouliot
Date: 2006-06-14 11:26:34 -0400 (Wed, 14 Jun 2006)
New Revision: 61697
Modified:
Log:
2006-06-14 Sebastien Pouliot <sebastien (AT) ximian (DOT) com>
* AuthenticodeBase.cs: Fix destination offset. Note that this works
under MS but not under Mono.
* AuthenticodeDeformatter.cs: Report a more useful error if the file
hash doesn't match the signed hash.
* AuthenticodeFormatter.cs: Implemented support for Timestamp method.
Modified:
2006-06-14 15:22:57 UTC (rev 61696)
2006-06-14 15:26:34 UTC (rev 61697)
@@ -182,7 +182,7 @@
}
else {
// hash the last part of the first (already in memory) block
-hash.TransformBlock (fileblock, pe, blockLength - pe, fileblock, 0);
+hash.TransformBlock (fileblock, pe, blockLength - pe, fileblock, pe);
// hash by blocks of 4096 bytes
long blocks = (n >12);
Modified:
2006-06-14 15:22:57 UTC (rev 61696)
2006-06-14 15:26:34 UTC (rev 61697)
@@ -210,8 +210,10 @@
}
base.Close ();
-if (!signedHash.CompareValue (hash))
+if (!signedHash.CompareValue (hash)) {
+reason = 2;
return false;
+}
// messageDigest is a hash of spcIndirectDataContext (which includes the file hash)
byte[] spcIDC = spc [0].Value;
Modified:
2006-06-14 15:22:57 UTC (rev 61696)
2006-06-14 15:26:34 UTC (rev 61697)
@@ -219,13 +219,60 @@
(Attribute (countersignature, ts[1][0][4][0]));
}
-public bool Sign (string fileName)
+private byte[] Timestamp (byte[] signature)
{
-string hashAlgorithm = "MD5";
-byte[] file = null;
+ASN1 tsreq = TimestampRequest (signature);
+WebClient wc = new WebClient ();
+wc.Headers.Add ("Content-Type", "application/octet-stream");
+wc.Headers.Add ("Accept", "application/octet-stream");
+byte[] tsdata = Encoding.ASCII.GetBytes (Convert.ToBase64String (tsreq.GetBytes ()));
+return wc.UploadData (timestamp.ToString (), tsdata);
+}
+private byte[] file;
+private int pe_offset = -1;
+private int sec_offset = -1;
+private int sec_size = -1;
+
+private int PE {
+get {
+if (file == null)
+return -1;
+if (pe_offset == -1) {
+int = BitConverterLE.ToInt32 (file, 60);
+if ( < file.Length)
+pe_offset = ;
+}
+return pe_offset;
+}
+}
+
+private int S {
+get {
+if (file == null)
+return -1;
+if (sec_offset == -1) {
+sec_offset = BitConverterLE.ToInt32 (file, PE + 152);
+}
+return sec_offset;
+}
+}
+
+private int SecuritySize {
+get {
+if (file == null)
+return -1;
+if (sec_size == -1) {
+sec_size = BitConverterLE.ToInt32 (file, PE + 156);
+}
+return sec_size;
+}
+}
+
+private bool (string fileName)
+{
using (FileStream fs = new FileStream (fileName, FileM, FileAccess.Read, FileShare.Read)) {
-file = new byte [fs.Length];
+file = new byte[fs.Length];
fs.Read (file, 0, file.Length);
fs.Close ();
}
@@ -234,58 +281,27 @@
if (BitConverterLE.ToUInt16 (file, 0) != 0x5A4D)
return false;
-// find offset of PE header
-int = BitConverterLE.ToInt32 (file, 60);
-if ( file.Length)
+// PE Header
+if (PE == -1)
return false;
// PE - NT header
-if (BitConverterLE.ToUInt16 (file, ) != 0x4550)
+if (BitConverterLE.ToUInt16 (file, PE) != 0x4550)
return false;
// IMAGE_DIRECTRY_ENTRY_SECURITY
-int dirS = BitConverterLE.ToInt32 (file, + 152);
-int dirSecuritySize = BitConverterLE.ToInt32 (file, + 156);
-
-if (dirSecuritySize 8) {
-entry = new byte [dirSecuritySize - 8];
-Buffer.BlockCopy (file, dirS + 8, entry, 0, entry.Length);
-}
-else
+if (SecuritySize 8) {
+entry = new byte[SecuritySize - 8];
+Buffer.BlockCopy (file, S + 8, entry, 0, entry.Length);
+} else
entry = null;
-HashAlgorithm hash = HashAlgorithm.Create (hashAlgorithm);
-// 0 to 215 (216) then skip 4 (checksum)
-int pe = + 88;
-hash.TransformBlock (file, 0, pe, file, 0);
-pe += 4;
-// 220 to 279 (60) then skip 8 (IMAGE_DIRECTRY_ENTRY_SECURITY)
-hash.TransformBlock (file, pe, 60, file, pe);
-pe += 68;
-// 288 to end of file
-int n = file.Length - pe;
-// minus any authenticode signature (with 8 bytes header)
-if (dirS != 0)
-n -= (dirSecuritySize);
-hash.TransformFinalBlock (file, pe, n);
+return true;
+}
-//
-byte[] signature = Header (hash.Hash, hashAlgorithm);
-if (timestamp != null) {
-ASN1 tsreq = TimestampRequest (signature);
-WebClient wc = new WebClient ();
-wc.Headers.Add ("Content-Type", "application/octet-stream");
-wc.Headers.Add ("Accept", "application/octet-stream");
-byte[] tsdata = Encoding.ASCII.GetBytes (Convert.ToBase64String (tsreq.GetBytes ()));
-byte[] tsres = wc.UploadData (timestamp.ToString (), tsdata);
-ProcessTimestamp (tsres);
-}
-PKCS7.ContentInfo sign = new PKCS7.ContentInfo (signedData);
-sign.Content.Add (pkcs7.ASN1);
-authenticode = sign.ASN1;
-
-byte[] asn = authenticode.GetBytes ();
-#if DEBUG
+private bool Save (string fileName, byte[] asn)
+{
+#if !DEBUG
using (FileStream fs = F (fileName + ".sig", FileMode.Create, FileAccess.Write)) {
fs.Write (asn, 0, asn.Length);
fs.Close ();
@@ -295,13 +311,13 @@
File.Copy (fileName, fileName + ".bak", true);
using (FileStream fs = F (fileName, FileMode.Create, FileAccess.Write)) {
-int filesize = (dirS == 0) ? file.Length : dirS;
+int filesize = (S == 0) ? file.Length : S;
// IMAGE_DIRECTRY_ENTRY_SECURITY (offset, size)
byte[] data = BitConverterLE.GetBytes (filesize);
-file [ + 152] = data [0];
-file [ + 153] = data [1];
-file [ + 154] = data [2];
-file [ + 155] = data [3];
+file[PE + 152] = data[0];
+file[PE + 153] = data[1];
+file[PE + 154] = data[2];
+file[PE + 155] = data[3];
int size = asn.Length + 8;
// must be a multiple of 8 bytes
int addsize = (size % 8);
@@ -309,27 +325,113 @@
addsize = 8 - addsize;
size += addsize;
data = BitConverterLE.GetBytes (size);// header
-file [ + 156] = data [0];
-file [ + 157] = data [1];
-file [ + 158] = data [2];
-file [ + 159] = data [3];
+file[PE + 156] = data[0];
+file[PE + 157] = data[1];
+file[PE + 158] = data[2];
+file[PE + 159] = data[3];
fs.Write (file, 0, filesize);
fs.Write (data, 0, data.Length);// length (again)
data = BitConverterLE.GetBytes (0x00020200);// magic
fs.Write (data, 0, data.Length);
fs.Write (asn, 0, asn.Length);
// fill up
-byte[] fillup = new byte [addsize];
+byte[] fillup = new byte[addsize];
fs.Write (fillup, 0, fillup.Length);
fs.Close ();
}
return true;
}
+public bool Sign (string fileName)
+{
+try {
+if (! (fileName))
+return false;
+
+HashAlgorithm hash = HashAlgorithm.Create (Hash);
+// 0 to 215 (216) then skip 4 (checksum)
+int pe = PE + 88;
+hash.TransformBlock (file, 0, pe, file, 0);
+pe += 4;
+// 220 to 279 (60) then skip 8 (IMAGE_DIRECTRY_ENTRY_SECURITY)
+hash.TransformBlock (file, pe, 60, file, pe);
+pe += 68;
+// 288 to end of file
+int n = file.Length - pe;
+// minus any authenticode signature (with 8 bytes header)
+if (S != 0)
+n -= (SecuritySize);
+hash.TransformFinalBlock (file, pe, n);
+
+byte[] signature = Header (hash.Hash, Hash);
+if (timestamp != null) {
+byte[] ts = Timestamp (signature);
+// add timestamp information inside the current pkcs7 SignedData instance
+// (this is possible because the data isn't yet signed)
+ProcessTimestamp (ts);
+}
+
+PKCS7.ContentInfo sign = new PKCS7.ContentInfo (signedData);
+sign.Content.Add (pkcs7.ASN1);
+authenticode = sign.ASN1;
+
+return Save (fileName, authenticode.GetBytes ());
+}
+catch (Exception e) {
+Console.WriteLine (e);
+}
+return false;
+}
+
// in case we just want to timestamp the file
public bool Timestamp (string fileName)
{
-return true;
+try {
+AuthenticodeDeformatter def = new AuthenticodeDeformatter (fileName);
+byte[] signature = def.Signature;
+if ((signature != null) && (fileName)) {
+PKCS7.ContentInfo ci = new PKCS7.ContentInfo (signature);
+pkcs7 = new PKCS7.SignedData (ci.Content);
+
+byte[] response = Timestamp (pkcs7.SignerInfo.Signature);
+ASN1 ts = new ASN1 (Convert.FromBase64String (Encoding.ASCII.GetString (response)));
+// insert new certificates and countersignature into the original signature
+ASN1 asn = new ASN1 (signature);
+ASN1 content = asn.Element (1, 0xA0);
+if (content == null)
+return false;
+
+ASN1 signedData = content.Element (0, 0x30);
+if (signedData == null)
+return false;
+
+// add the supplied certificates inside our signature
+ASN1 certificates = signedData.Element (3, 0xA0);
+if (certificates == null) {
+certificates = new ASN1 (0xA0);
+signedData.Add (certificates);
+}
+for (int i = 0; i < ts[1][0][3].Count; i++) {
+certificates.Add (ts[1][0][3][i]);
+}
+
+// add an unauthentified attribute to our signature
+ASN1 signerInfoSet = signedData[signedData.Count - 1];
+ASN1 signerInfo = signerInfoSet[0];
+ASN1 unauthenticated = signerInfo[signerInfo.Count - 1];
+if (unauthenticated.Tag != 0xA1) {
+unauthenticated = new ASN1 (0xA1);
+signerInfo.Add (unauthenticated);
+}
+unauthenticated.Add (Attribute (countersignature, ts[1][0][4][0]));
+
+return Save (fileName, asn.GetBytes ());
+}
+}
+catch (Exception e) {
+Console.WriteLine (e);
+}
+return false;
}
}
}
Modified:
2006-06-14 15:22:57 UTC (rev 61696)
2006-06-14 15:26:34 UTC (rev 61697)
@@ -1,3 +1,11 @@
+2006-06-14 Sebastien Pouliot <sebastien (AT) ximian (DOT) com>
+
+* AuthenticodeBase.cs: Fix destination offset. Note that this works
+under MS but not under Mono.
+* AuthenticodeDeformatter.cs: Report a more useful error if the file
+hash doesn't match the signed hash.
+* AuthenticodeFormatter.cs: Implemented support for Timestamp method.
+
2005-04-18 Sebastien Pouliot <sebastien (AT) ximian (DOT) com>
* AuthenticodeFormatter.cs: Commented unused private constants to
Mono-patches maillist - Mono-patches (AT) lists (DOT) ximian.com