Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/3.1.3/EPPlus-3.1.3/VBA/ExcelVBASignature.cs @ 10760

Last change on this file since 10760 was 9580, checked in by sforsten, 11 years ago

#1730:

  • added SymbolicDataAnalysisExpressionExcelFormatter
  • changed modifiers in SymbolicExpressionTreeChart of methods SaveImageAsBitmap and SaveImageAsEmf to public
  • added menu item ExportSymbolicSolutionToExcelMenuItem to export a symbolic solution to an excel file
  • added EPPlus-3.1.3 to ExtLibs
File size: 14.3 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.Packaging;
39using System.IO;
40
41namespace OfficeOpenXml.VBA
42{
43    /// <summary>
44    /// The code signature properties of the project
45    /// </summary>
46    public class ExcelVbaSignature
47    {
48        const string schemaRelVbaSignature = "http://schemas.microsoft.com/office/2006/relationships/vbaProjectSignature";
49        PackagePart _vbaPart = null;
50        internal ExcelVbaSignature(PackagePart vbaPart)
51        {
52            _vbaPart = vbaPart;
53            GetSignature();
54        }
55        private void GetSignature()
56        {
57            if (_vbaPart == null) return;
58            var rel = _vbaPart.GetRelationshipsByType(schemaRelVbaSignature).FirstOrDefault();
59            if (rel != null)
60            {
61                Uri = PackUriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
62                Part = _vbaPart.Package.GetPart(Uri);
63
64                var stream = Part.GetStream();
65                BinaryReader br = new BinaryReader(stream);
66                uint cbSignature = br.ReadUInt32();       
67                uint signatureOffset = br.ReadUInt32();     //44 ??
68                uint cbSigningCertStore = br.ReadUInt32(); 
69                uint certStoreOffset = br.ReadUInt32();     
70                uint cbProjectName = br.ReadUInt32();       
71                uint projectNameOffset = br.ReadUInt32();   
72                uint fTimestamp = br.ReadUInt32();
73                uint cbTimestampUrl = br.ReadUInt32();
74                uint timestampUrlOffset = br.ReadUInt32(); 
75                byte[] signature = br.ReadBytes((int)cbSignature);
76                uint version = br.ReadUInt32();
77                uint fileType = br.ReadUInt32();
78
79                uint id = br.ReadUInt32();
80                while (id != 0)
81                {
82                    uint encodingType = br.ReadUInt32();
83                    uint length = br.ReadUInt32();
84                    if (length > 0)
85                    {
86                        byte[] value = br.ReadBytes((int)length);
87                        switch (id)
88                        {
89                            //Add property values here...
90                            case 0x20:
91                                Certificate = new X509Certificate2(value);
92                                break;
93                            default:
94                                break;
95                        }
96                    }
97                    id = br.ReadUInt32();
98                }
99                uint endel1 = br.ReadUInt32();  //0
100                uint endel2 = br.ReadUInt32();  //0
101                ushort rgchProjectNameBuffer = br.ReadUInt16();
102                ushort rgchTimestampBuffer = br.ReadUInt16();
103                Verifier = new SignedCms();
104                Verifier.Decode(signature);
105            }
106            else
107            {
108                Certificate = null;
109                Verifier = null;
110            }
111        }
112        //Create Oid from a bytearray
113        //private string ReadHash(byte[] content)
114        //{
115        //    StringBuilder builder = new StringBuilder();
116        //    int offset = 0x6;
117        //    if (0 < (content.Length))
118        //    {
119        //        byte num = content[offset];
120        //        byte num2 = (byte)(num / 40);
121        //        builder.Append(num2.ToString(null, null));
122        //        builder.Append(".");
123        //        num2 = (byte)(num % 40);
124        //        builder.Append(num2.ToString(null, null));
125        //        ulong num3 = 0L;
126        //        for (int i = offset + 1; i < content.Length; i++)
127        //        {
128        //            num2 = content[i];
129        //            num3 = (ulong)(ulong)(num3 << 7) + ((byte)(num2 & 0x7f));
130        //            if ((num2 & 0x80) == 0)
131        //            {
132        //                builder.Append(".");
133        //                builder.Append(num3.ToString(null, null));
134        //                num3 = 0L;
135        //            }
136        //            //1.2.840.113549.2.5
137        //        }
138        //    }
139
140
141        //    string oId = builder.ToString();
142
143        //    return oId;
144        //}
145        internal void Save(ExcelVbaProject proj)
146        {
147            if (Certificate == null || Certificate.HasPrivateKey==false)    //No signature. Remove any Signature part
148            {
149                if (Part != null)
150                {
151                    foreach (var r in Part.GetRelationships())
152                    {
153                        Part.DeleteRelationship(r.Id);
154                    }
155                    Part.Package.DeletePart(Part.Uri);
156                }
157                return;
158            }
159            var ms = new MemoryStream();
160            var bw = new BinaryWriter(ms);
161
162            byte[] certStore = GetCertStore();
163
164            byte[] cert = SignProject(proj);
165            bw.Write((uint)cert.Length);
166            bw.Write((uint)44);                  //?? 36 ref inside cert ??
167            bw.Write((uint)certStore.Length);    //cbSigningCertStore
168            bw.Write((uint)(cert.Length + 44));  //certStoreOffset
169            bw.Write((uint)0);                   //cbProjectName
170            bw.Write((uint)(cert.Length + certStore.Length + 44));    //projectNameOffset
171            bw.Write((uint)0);    //fTimestamp
172            bw.Write((uint)0);    //cbTimestampUrl
173            bw.Write((uint)(cert.Length + certStore.Length + 44 + 2));    //timestampUrlOffset
174            bw.Write(cert);
175            bw.Write(certStore);
176            bw.Write((ushort)0);//rgchProjectNameBuffer
177            bw.Write((ushort)0);//rgchTimestampBuffer
178            bw.Write((ushort)0);
179            bw.Flush();
180
181            var rel = proj.Part.GetRelationshipsByType(schemaRelVbaSignature).FirstOrDefault();
182            if (Part == null)
183            {
184
185                if (rel != null)
186                {
187                    Uri = rel.TargetUri;
188                    Part = proj._pck.GetPart(rel.TargetUri);
189                }
190                else
191                {
192                    Uri = new Uri("/xl/vbaProjectSignature.bin", UriKind.Relative);
193                    Part = proj._pck.CreatePart(Uri, ExcelPackage.schemaVBASignature);
194                }
195            }
196            if (rel == null)
197            {
198                proj.Part.CreateRelationship(PackUriHelper.ResolvePartUri(proj.Uri, Uri), TargetMode.Internal, schemaRelVbaSignature);               
199            }
200            var b = ms.ToArray();
201            Part.GetStream(FileMode.Create).Write(b, 0, b.Length);           
202        }
203
204        private byte[] GetCertStore()
205        {
206            var ms = new MemoryStream();
207            var bw = new BinaryWriter(ms);
208
209            bw.Write((uint)0); //Version
210            bw.Write((uint)0x54524543); //fileType
211
212            //SerializedCertificateEntry
213            var certData = Certificate.RawData;
214            bw.Write((uint)0x20);
215            bw.Write((uint)1);
216            bw.Write((uint)certData.Length);
217            bw.Write(certData);
218
219            //EndElementMarkerEntry
220            bw.Write((uint)0);
221            bw.Write((ulong)0);
222
223            bw.Flush();
224            return ms.ToArray();
225        }
226
227        private void WriteProp(BinaryWriter bw, int id, byte[] data)
228        {
229            bw.Write((uint)id);
230            bw.Write((uint)1);
231            bw.Write((uint)data.Length);
232            bw.Write(data);
233        }
234        internal byte[] SignProject(ExcelVbaProject proj)
235        {
236            if (!Certificate.HasPrivateKey)
237            {
238                //throw (new InvalidOperationException("The certificate doesn't have a private key"));
239                Certificate = null;
240                return null;
241            }
242            var hash = GetContentHash(proj);
243
244            BinaryWriter bw = new BinaryWriter(new MemoryStream());
245            bw.Write((byte)0x30); //Constructed Type
246            bw.Write((byte)0x32); //Total length
247            bw.Write((byte)0x30); //Constructed Type
248            bw.Write((byte)0x0E); //Length SpcIndirectDataContent
249            bw.Write((byte)0x06); //Oid Tag Indentifier
250            bw.Write((byte)0x0A); //Lenght OId
251            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
252            bw.Write((byte)0x04);   //Octet String Tag Identifier
253            bw.Write((byte)0x00);   //Zero length
254
255            bw.Write((byte)0x30); //Constructed Type (DigestInfo)
256            bw.Write((byte)0x20); //Length DigestInfo
257            bw.Write((byte)0x30); //Constructed Type (Algorithm)
258            bw.Write((byte)0x0C); //length AlgorithmIdentifier
259            bw.Write((byte)0x06); //Oid Tag Indentifier
260            bw.Write((byte)0x08); //Lenght OId
261            bw.Write(new byte[] { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05 }); //Encoded Oid for 1.2.840.113549.2.5 (AlgorithmIdentifier MD5)
262            bw.Write((byte)0x05);   //Null type identifier
263            bw.Write((byte)0x00);   //Null length
264            bw.Write((byte)0x04);   //Octet String Identifier
265            bw.Write((byte)hash.Length);   //Hash length
266            bw.Write(hash);                //Content hash
267
268            ContentInfo contentInfo = new ContentInfo(((MemoryStream)bw.BaseStream).ToArray());
269            contentInfo.ContentType.Value = "1.3.6.1.4.1.311.2.1.4";
270            Verifier = new SignedCms(contentInfo);
271            var signer = new CmsSigner(Certificate);
272            Verifier.ComputeSignature(signer, false);
273            return Verifier.Encode();
274        }
275
276        private byte[] GetContentHash(ExcelVbaProject proj)
277        {
278            //MS-OVBA 2.4.2
279            var enc = System.Text.Encoding.GetEncoding(proj.CodePage);
280            BinaryWriter bw = new BinaryWriter(new MemoryStream());
281            bw.Write(enc.GetBytes(proj.Name));
282            bw.Write(enc.GetBytes(proj.Constants));
283            foreach (var reference in proj.References)
284            {
285                if (reference.ReferenceRecordID == 0x0D)
286                {
287                    bw.Write((byte)0x7B);
288                }
289                if (reference.ReferenceRecordID == 0x0E)
290                {
291                    //var r = (ExcelVbaReferenceProject)reference;
292                    //BinaryWriter bwTemp = new BinaryWriter(new MemoryStream());
293                    //bwTemp.Write((uint)r.Libid.Length);
294                    //bwTemp.Write(enc.GetBytes(r.Libid));             
295                    //bwTemp.Write((uint)r.LibIdRelative.Length);
296                    //bwTemp.Write(enc.GetBytes(r.LibIdRelative));
297                    //bwTemp.Write(r.MajorVersion);
298                    //bwTemp.Write(r.MinorVersion);
299                    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.
300                    {
301                        if (b != 0)
302                        {
303                            bw.Write(b);
304                        }
305                        else
306                        {
307                            break;
308                        }
309                    }
310                }
311            }
312            foreach (var module in proj.Modules)
313            {
314                var lines = module.Code.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
315                foreach (var line in lines)
316                {
317                    if (!line.StartsWith("attribute", true, null))
318                    {
319                        bw.Write(enc.GetBytes(line));
320                    }
321                }
322            }
323            var buffer = (bw.BaseStream as MemoryStream).ToArray();
324            var hp = System.Security.Cryptography.MD5CryptoServiceProvider.Create();
325            return hp.ComputeHash(buffer);
326        }
327        /// <summary>
328        /// The certificate to sign the VBA project.
329        /// <remarks>
330        /// This certificate must have a private key.
331        /// 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).
332        /// </remarks>
333        /// </summary>
334        public X509Certificate2 Certificate { get; set; }
335        /// <summary>
336        /// The verifier
337        /// </summary>
338        public SignedCms Verifier { get; internal set; }
339        internal CompoundDocument Signature { get; set; }
340        internal PackagePart Part { get; set; }
341        internal Uri Uri { get; private set; }
342    }
343}
Note: See TracBrowser for help on using the repository browser.