Free cookie consent management tool by TermsFeed Policy Generator

source: branches/GBT/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/VBA/ExcelVbaSignature.cs @ 12495

Last change on this file since 12495 was 12495, checked in by gkronber, 9 years ago

#2261: merged trunk changes to branch
r12494
#2403: added a null check in the MatlabParameterVectorEvaluator to prevent exceptions when clearstate is called


r12493
#2369: added support for squared errors and relative errors to error-characteristic-curve view


r12492
#2392: implemented PearsonsRCalculator to fix incorrect correlation values in the correlation matrix.


r12491
#2402 don't set task state to waiting when it fails


r12490
#2401 added missing Mono.Cecil plugin dependency


r12488
#2400 - Interfaces for Capaciated-, PickupAndDelivery- and TimeWindowed-ProblemInstances now specify an additional penalty parameter to set the current penalty factor for the constraint relaxation. - The setter of the penalty-property in ...


r12485
#2374 made RegressionSolution and ClassificationSolution non-abstract


r12482
#2320: Fixed warnings in unit test solutions introduced in r12420 by marking methods as obsolete.


r12481
#2320: Fixed AfterDeserialization of GEArtifialAntEvaluator.


r12480
#2320: Fixed error in symbolicexpressiontree crossover regarding the wiring of lookup parameters if persisted file is loaded.


r12479
#2397 moved GeoIP project into ExtLibs


r12478
#2329 fixed bug in simple code editor


r12476
#2331 removed outdated plugins


r12475
#2368 fixed compile warnings


r12474
#2399 worked on Mono project prepare script


r12473
#2329 added a simple code editor for Linux


r12472
#2399 - fixed MathJax.js file name - worked on Mono project prepare script


r12471
#2399 worked on Mono project prepare script


r12470
#2399 fixed pre-build events in project files


r12465
#2399 worked on mono project prepare script


r12464
#2399 added patch to project


r12463
#2399 fixed EPPlus so that it compiles on Linux


r12461
#2398: Skip root and start symbols when calculating impacts and replacement values in the pruning operators.


r12458
#2354 show label when no data is displayed and don't show the legend


r12457
#2353 removed duplicated call to Any() in Hive Status page


r12456
#2368 fixed modifier


r12455
#2368 added support in persistence for typecaches in streams


r12445
#2394: Changed Web.config compilation from debug to release to force script bundling. Changed history loading type from lazy to eager loading to increase performance. Fixed "getCoreStatus" typo in statusCtrl.js


r12443
#2394: Fixed UserTaskQuery and GetStatusHistory in the WebApp.Status plugin


r12442
#2394 added nuget folders to svn ignore list


r12435
#2394: Improved PluginManager and updated hive status monitor.


r12434
#2396 added symbolic expression tree formatter for C#


r12433
#2395: Minor change in DoubleValue.GetValue.


r12432
#2395 Use simple round-trip format for doubles because G17 prints some strange numbers (20.22 to 20.219999999999999999). Some accuracy can still be lost on 64bit machines, but should be very rare and minimal. double.MaxValue can still be pa...


r12431
#2395 Fixed parsing issues by using the G17 format.


r12430
#2394 added missing package config


r12429
#2394 added missing package config


r12428
#2394 added web app and status page to trunk


r12424
#2320: Adapted plugin file and updated project file of SymbolicExpressionTreeEncoding.


r12422
#2320: Merged the encoding class and all accompanying changes in the trunk.


r12401
#2387 Fixed a bug where the automatic selection of the first element behaved differently for the NewItemDialog.


r12400
#2387 Forgot to commit a file.


r12399
#2387 - Added context-menu for expanding and collapsing tree-nodes. - Improve response time when expanding/collapsing all nodes for TypeSelector and NewItemDialog.


r12398
#2387 - Added clearSearch-button in TypeSelector. - Adapted behavior of TypeSelector and NewItemDialog that a selected node stays selected as long as it matches the search criteria.


r12397
#2387 - Adapted behavior of the matching in the TypeSelector that it behave the same as the NewItemDialog. The search string is tokenized by space and matches if all tokens are contained, (eg. "Sym Reg" matches "SymbolicRegression...")...


r12393
#2025 - Removed Expand/CollapseAll buttons. - Removed cycling of items.


r12392
#2386: Updated GetHashCode method in the EnumerableBoolEqualityComparer.


File size: 15.6 KB
Line 
1/*******************************************************************************
2 * You may amend and distribute as you like, but don't remove this header!
3 *
4 * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
5 * See http://www.codeplex.com/EPPlus for details.
6 *
7 * Copyright (C) 2011  Jan Källman
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
17 * See the GNU Lesser General Public License for more details.
18 *
19 * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
20 * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
21 *
22 * All code and executables are provided "as is" with no warranty either express or implied.
23 * The author accepts no liability for any damage or loss of business that this product may cause.
24 *
25 * Code change notes:
26 *
27 * Author             Change            Date
28 *******************************************************************************
29 * Jan Källman    Added   26-MAR-2012
30 *******************************************************************************/
31using System;
32using System.Collections.Generic;
33using System.Linq;
34using System.Text;
35using System.Security.Cryptography.X509Certificates;
36using System.Security.Cryptography.Pkcs;
37using OfficeOpenXml.Utils;
38using System.IO;
39
40namespace OfficeOpenXml.VBA
41{
42    /// <summary>
43    /// The code signature properties of the project
44    /// </summary>
45    public class ExcelVbaSignature
46    {
47        const string schemaRelVbaSignature = "http://schemas.microsoft.com/office/2006/relationships/vbaProjectSignature";
48        Packaging.ZipPackagePart _vbaPart = null;
49        internal ExcelVbaSignature(Packaging.ZipPackagePart vbaPart)
50        {
51            _vbaPart = vbaPart;
52            GetSignature();
53        }
54        private void GetSignature()
55        {
56            if (_vbaPart == null) return;
57            var rel = _vbaPart.GetRelationshipsByType(schemaRelVbaSignature).FirstOrDefault();
58            if (rel != null)
59            {
60                Uri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
61                Part = _vbaPart.Package.GetPart(Uri);
62
63                var stream = Part.GetStream();
64                BinaryReader br = new BinaryReader(stream);
65                uint cbSignature = br.ReadUInt32();       
66                uint signatureOffset = br.ReadUInt32();     //44 ??
67                uint cbSigningCertStore = br.ReadUInt32(); 
68                uint certStoreOffset = br.ReadUInt32();     
69                uint cbProjectName = br.ReadUInt32();       
70                uint projectNameOffset = br.ReadUInt32();   
71                uint fTimestamp = br.ReadUInt32();
72                uint cbTimestampUrl = br.ReadUInt32();
73                uint timestampUrlOffset = br.ReadUInt32(); 
74                byte[] signature = br.ReadBytes((int)cbSignature);
75                uint version = br.ReadUInt32();
76                uint fileType = br.ReadUInt32();
77
78                uint id = br.ReadUInt32();
79                while (id != 0)
80                {
81                    uint encodingType = br.ReadUInt32();
82                    uint length = br.ReadUInt32();
83                    if (length > 0)
84                    {
85                        byte[] value = br.ReadBytes((int)length);
86                        switch (id)
87                        {
88                            //Add property values here...
89                            case 0x20:
90                                Certificate = new X509Certificate2(value);
91                                break;
92                            default:
93                                break;
94                        }
95                    }
96                    id = br.ReadUInt32();
97                }
98                uint endel1 = br.ReadUInt32();  //0
99                uint endel2 = br.ReadUInt32();  //0
100                ushort rgchProjectNameBuffer = br.ReadUInt16();
101                ushort rgchTimestampBuffer = br.ReadUInt16();
102                Verifier = new SignedCms();
103                Verifier.Decode(signature);
104            }
105            else
106            {
107                Certificate = null;
108                Verifier = null;
109            }
110        }
111        //Create Oid from a bytearray
112        //private string ReadHash(byte[] content)
113        //{
114        //    StringBuilder builder = new StringBuilder();
115        //    int offset = 0x6;
116        //    if (0 < (content.Length))
117        //    {
118        //        byte num = content[offset];
119        //        byte num2 = (byte)(num / 40);
120        //        builder.Append(num2.ToString(null, null));
121        //        builder.Append(".");
122        //        num2 = (byte)(num % 40);
123        //        builder.Append(num2.ToString(null, null));
124        //        ulong num3 = 0L;
125        //        for (int i = offset + 1; i < content.Length; i++)
126        //        {
127        //            num2 = content[i];
128        //            num3 = (ulong)(ulong)(num3 << 7) + ((byte)(num2 & 0x7f));
129        //            if ((num2 & 0x80) == 0)
130        //            {
131        //                builder.Append(".");
132        //                builder.Append(num3.ToString(null, null));
133        //                num3 = 0L;
134        //            }
135        //            //1.2.840.113549.2.5
136        //        }
137        //    }
138
139
140        //    string oId = builder.ToString();
141
142        //    return oId;
143        //}
144        internal void Save(ExcelVbaProject proj)
145        {
146            if (Certificate == null)
147            {
148                return;
149            }
150           
151            if (Certificate.HasPrivateKey==false)    //No signature. Remove any Signature part
152            {
153                var storeCert = GetCertFromStore(StoreLocation.CurrentUser);
154                if (storeCert == null)
155                {
156                    storeCert = GetCertFromStore(StoreLocation.LocalMachine);
157                }
158                if (storeCert != null && storeCert.HasPrivateKey == true)
159                {
160                    Certificate = storeCert;
161                }
162                else
163                {
164                    foreach (var r in Part.GetRelationships())
165                    {
166                        Part.DeleteRelationship(r.Id);
167                    }
168                    Part.Package.DeletePart(Part.Uri);
169                    return;
170                }
171            }
172            var ms = new MemoryStream();
173            var bw = new BinaryWriter(ms);
174
175            byte[] certStore = GetCertStore();
176
177            byte[] cert = SignProject(proj);
178            bw.Write((uint)cert.Length);
179            bw.Write((uint)44);                  //?? 36 ref inside cert ??
180            bw.Write((uint)certStore.Length);    //cbSigningCertStore
181            bw.Write((uint)(cert.Length + 44));  //certStoreOffset
182            bw.Write((uint)0);                   //cbProjectName
183            bw.Write((uint)(cert.Length + certStore.Length + 44));    //projectNameOffset
184            bw.Write((uint)0);    //fTimestamp
185            bw.Write((uint)0);    //cbTimestampUrl
186            bw.Write((uint)(cert.Length + certStore.Length + 44 + 2));    //timestampUrlOffset
187            bw.Write(cert);
188            bw.Write(certStore);
189            bw.Write((ushort)0);//rgchProjectNameBuffer
190            bw.Write((ushort)0);//rgchTimestampBuffer
191            bw.Write((ushort)0);
192            bw.Flush();
193
194            var rel = proj.Part.GetRelationshipsByType(schemaRelVbaSignature).FirstOrDefault();
195            if (Part == null)
196            {
197
198                if (rel != null)
199                {
200                    Uri = rel.TargetUri;
201                    Part = proj._pck.GetPart(rel.TargetUri);
202                }
203                else
204                {
205                    Uri = new Uri("/xl/vbaProjectSignature.bin", UriKind.Relative);
206                    Part = proj._pck.CreatePart(Uri, ExcelPackage.schemaVBASignature);
207                }
208            }
209            if (rel == null)
210            {
211                proj.Part.CreateRelationship(UriHelper.ResolvePartUri(proj.Uri, Uri), Packaging.TargetMode.Internal, schemaRelVbaSignature);               
212            }
213            var b = ms.ToArray();
214            Part.GetStream(FileMode.Create).Write(b, 0, b.Length);           
215        }
216
217        private X509Certificate2 GetCertFromStore(StoreLocation loc)
218        {
219            try
220            {
221                X509Store store = new X509Store(loc);
222                store.Open(OpenFlags.ReadOnly);
223                try
224                {
225                    var storeCert = store.Certificates.Find(
226                                    X509FindType.FindByThumbprint,
227                                    Certificate.Thumbprint,
228                                    true
229                                    ).OfType<X509Certificate2>().FirstOrDefault();
230                    return storeCert;
231                }
232                finally
233                {
234                    store.Close();
235                }
236            }
237            catch
238            {
239                return null;
240            }
241        }
242
243        private byte[] GetCertStore()
244        {
245            var ms = new MemoryStream();
246            var bw = new BinaryWriter(ms);
247
248            bw.Write((uint)0); //Version
249            bw.Write((uint)0x54524543); //fileType
250
251            //SerializedCertificateEntry
252            var certData = Certificate.RawData;
253            bw.Write((uint)0x20);
254            bw.Write((uint)1);
255            bw.Write((uint)certData.Length);
256            bw.Write(certData);
257
258            //EndElementMarkerEntry
259            bw.Write((uint)0);
260            bw.Write((ulong)0);
261
262            bw.Flush();
263            return ms.ToArray();
264        }
265
266        private void WriteProp(BinaryWriter bw, int id, byte[] data)
267        {
268            bw.Write((uint)id);
269            bw.Write((uint)1);
270            bw.Write((uint)data.Length);
271            bw.Write(data);
272        }
273        internal byte[] SignProject(ExcelVbaProject proj)
274        {
275            if (!Certificate.HasPrivateKey)
276            {
277                //throw (new InvalidOperationException("The certificate doesn't have a private key"));
278                Certificate = null;
279                return null;
280            }
281            var hash = GetContentHash(proj);
282
283            BinaryWriter bw = new BinaryWriter(new MemoryStream());
284            bw.Write((byte)0x30); //Constructed Type
285            bw.Write((byte)0x32); //Total length
286            bw.Write((byte)0x30); //Constructed Type
287            bw.Write((byte)0x0E); //Length SpcIndirectDataContent
288            bw.Write((byte)0x06); //Oid Tag Indentifier
289            bw.Write((byte)0x0A); //Lenght OId
290            bw.Write(new byte[] { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x1D }); //Encoded Oid 1.3.6.1.4.1.311.2.1.29
291            bw.Write((byte)0x04);   //Octet String Tag Identifier
292            bw.Write((byte)0x00);   //Zero length
293
294            bw.Write((byte)0x30); //Constructed Type (DigestInfo)
295            bw.Write((byte)0x20); //Length DigestInfo
296            bw.Write((byte)0x30); //Constructed Type (Algorithm)
297            bw.Write((byte)0x0C); //length AlgorithmIdentifier
298            bw.Write((byte)0x06); //Oid Tag Indentifier
299            bw.Write((byte)0x08); //Lenght OId
300            bw.Write(new byte[] { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05 }); //Encoded Oid for 1.2.840.113549.2.5 (AlgorithmIdentifier MD5)
301            bw.Write((byte)0x05);   //Null type identifier
302            bw.Write((byte)0x00);   //Null length
303            bw.Write((byte)0x04);   //Octet String Identifier
304            bw.Write((byte)hash.Length);   //Hash length
305            bw.Write(hash);                //Content hash
306
307            ContentInfo contentInfo = new ContentInfo(((MemoryStream)bw.BaseStream).ToArray());
308            contentInfo.ContentType.Value = "1.3.6.1.4.1.311.2.1.4";
309            Verifier = new SignedCms(contentInfo);
310            var signer = new CmsSigner(Certificate);
311            Verifier.ComputeSignature(signer, false);
312            return Verifier.Encode();
313        }
314
315        private byte[] GetContentHash(ExcelVbaProject proj)
316        {
317            //MS-OVBA 2.4.2
318            var enc = System.Text.Encoding.GetEncoding(proj.CodePage);
319            BinaryWriter bw = new BinaryWriter(new MemoryStream());
320            bw.Write(enc.GetBytes(proj.Name));
321            bw.Write(enc.GetBytes(proj.Constants));
322            foreach (var reference in proj.References)
323            {
324                if (reference.ReferenceRecordID == 0x0D)
325                {
326                    bw.Write((byte)0x7B);
327                }
328                if (reference.ReferenceRecordID == 0x0E)
329                {
330                    //var r = (ExcelVbaReferenceProject)reference;
331                    //BinaryWriter bwTemp = new BinaryWriter(new MemoryStream());
332                    //bwTemp.Write((uint)r.Libid.Length);
333                    //bwTemp.Write(enc.GetBytes(r.Libid));             
334                    //bwTemp.Write((uint)r.LibIdRelative.Length);
335                    //bwTemp.Write(enc.GetBytes(r.LibIdRelative));
336                    //bwTemp.Write(r.MajorVersion);
337                    //bwTemp.Write(r.MinorVersion);
338                    foreach (byte b in BitConverter.GetBytes((uint)reference.Libid.Length))  //Length will never be an UInt with 4 bytes that aren't 0 (> 0x00FFFFFF), so no need for the rest of the properties.
339                    {
340                        if (b != 0)
341                        {
342                            bw.Write(b);
343                        }
344                        else
345                        {
346                            break;
347                        }
348                    }
349                }
350            }
351            foreach (var module in proj.Modules)
352            {
353                var lines = module.Code.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
354                foreach (var line in lines)
355                {
356                    if (!line.StartsWith("attribute", true, null))
357                    {
358                        bw.Write(enc.GetBytes(line));
359                    }
360                }
361            }
362            var buffer = (bw.BaseStream as MemoryStream).ToArray();
363            var hp = System.Security.Cryptography.MD5CryptoServiceProvider.Create();
364            return hp.ComputeHash(buffer);
365        }
366        /// <summary>
367        /// The certificate to sign the VBA project.
368        /// <remarks>
369        /// This certificate must have a private key.
370        /// There is no validation that the certificate is valid for codesigning, so make sure it's valid to sign Excel files (Excel 2010 is more strict that prior versions).
371        /// </remarks>
372        /// </summary>
373        public X509Certificate2 Certificate { get; set; }
374        /// <summary>
375        /// The verifier
376        /// </summary>
377        public SignedCms Verifier { get; internal set; }
378#if !MONO
379        internal CompoundDocument Signature { get; set; }
380#endif
381        internal Packaging.ZipPackagePart Part { get; set; }
382        internal Uri Uri { get; private set; }
383    }
384}
Note: See TracBrowser for help on using the repository browser.