Hi all,

 

I've noticed two bugs in insignia.exe yesterday (#3340 and #3341) and since
I had a little time, I had a look at the inscriber.cs and created a small
bug fix. If you're interested, here is a diff from the changes (sorry
haven't had the time to create a fork etc.). The diff is against WiX 3.7, as
I am still working with it. There were only little changes to inscriber.cs
lately anyways. 

 

 

diff -r 02d1730aa0bf src/wix/inscriber.cs

--- a/src/wix/inscriber.cs             Thu Nov 22 16:35:28 2012 +0100

+++ b/src/wix/inscriber.cs          Tue Jul 09 15:54:35 2013 +0200

@@ -211,12 +211,82 @@

                 int codepage = 1252;

 

                 // reset list of certificates seen for this database

-                Dictionary<string, object> certificates = new
Dictionary<string, object>();

+                Dictionary<string, string> certificates = new
Dictionary<string, string>();

 

                 // Reset the in-memory tables for this new database

                 Table digitalSignatureTable = new Table(null,
this.tableDefinitions["MsiDigitalSignature"]);

                 Table digitalCertificateTable = new Table(null,
this.tableDefinitions["MsiDigitalCertificate"]);

 

+                //Read existing certificates and add them again, with the
same identifier. We will also reuse the certificate

+                //if it is the same as one of the certificates used for
signing a media.

+                if (database.TableExists("MsiDigitalCertificate"))

+                {

+                    using (View certificatesView =
database.OpenExecuteView("SELECT * FROM MsiDigitalCertificate"))

+                    {

+                        while (true)

+                        {

+                            using (Record certificateRecord =
certificatesView.Fetch())

+                            {

+                                if (null == certificateRecord)

+                                {

+                                    break;

+                                }

+

+                                X509Certificate2 existingCert2 = null;

+                                string certId =
certificateRecord.GetString(1);

+

+                                //Read certificate to get the thumbprint

+                                using (MemoryStream msCert = new
MemoryStream())

+                                {

+                                    int bytesRead;

+                                    byte[] buffer = new byte[512];

+

+                                    while (0 != (bytesRead =
certificateRecord.GetStream(2, buffer, buffer.Length)))

+                                    {

+                                        msCert.Write(buffer, 0, bytesRead);

+                                    }

+

+                                    //Use the SignedCms class to load the
PKCS #7 certificate from the table.

+
System.Security.Cryptography.Pkcs.SignedCms s = new
System.Security.Cryptography.Pkcs.SignedCms();

+                                    s.Decode(msCert.ToArray());

+

+                                    //One certificate is expected here.

+                                    if (s.Certificates.Count > 0)

+                                    {

+                                        existingCert2 = s.Certificates[0];

+                                    }

+                                }

+

+                                // If we haven't added this cert to the
MsiDigitalCertificate table, set it up to be added

+                                if (existingCert2 != null &&
!certificates.ContainsKey(existingCert2.Thumbprint))

+                                {

+                                    // Add it to our "add to
MsiDigitalCertificate" table dictionary

+                                    Row digitalCertificateRow =
digitalCertificateTable.CreateRow(null);

+                                    //Keep identifier

+                                    digitalCertificateRow[0] = certId;

+

+                                    // Export to a file, because the MSI
API's require us to provide a file path on disk

+                                    string certPath =
Path.Combine(this.TempFilesLocation, "MsiDigitalCertificate");

+                                    Directory.CreateDirectory(certPath);

+                                    certPath = Path.Combine(certPath,
existingCert2.Thumbprint + ".cer");

+                                    File.Delete(certPath);

+

+                                    using (BinaryWriter writer = new
BinaryWriter(File.Open(certPath, FileMode.Create)))

+                                    {

+
writer.Write(existingCert2.RawData);

+                                        writer.Close();

+                                    }

+

+                                    // Now set the file path on disk where
this binary stream will be picked up at import time

+                                    digitalCertificateRow[1] =
existingCert2.Thumbprint + ".cer";

+

+
certificates.Add(existingCert2.Thumbprint, certId);

+                                }

+                            }

+                        }

+                    }

+                }

+

                 using (View mediaView = database.OpenExecuteView("SELECT *
FROM Media"))

                 {

                     while (true)

@@ -278,12 +348,17 @@

                                 }

                             }

 

+                            string certId;

+

                             // If we haven't added this cert to the
MsiDigitalCertificate table, set it up to be added

                             if
(!certificates.ContainsKey(cert2.Thumbprint))

                             {

                                 // Add it to our "add to
MsiDigitalCertificate" table dictionary

                                 Row digitalCertificateRow =
digitalCertificateTable.CreateRow(null);

-                                digitalCertificateRow[0] =
cert2.Thumbprint;

+

+                                //Create an unique identifier. We cannot
just use the thumbprint as it can start with a digit which is not a valid
identifier.

+                                certId = "cer" +
Guid.NewGuid().ToString("N").ToUpperInvariant();

+                                digitalCertificateRow[0] = certId;

 

                                 // Export to a file, because the MSI API's
require us to provide a file path on disk

                                 string certPath =
Path.Combine(this.TempFilesLocation, "MsiDigitalCertificate");

@@ -300,14 +375,19 @@

                                 // Now set the file path on disk where this
binary stream will be picked up at import time

                                 digitalCertificateRow[1] = cert2.Thumbprint
+ ".cer";

 

-                                certificates.Add(cert2.Thumbprint,
certPath);

+                                certificates.Add(cert2.Thumbprint, certId);

+                            }

+                            else

+                            {

+                                //Get existing cert ID

+                                certId = certificates[cert2.Thumbprint];

                             }

 

                             digitalSignatureRow =
digitalSignatureTable.CreateRow(null);

 

                             digitalSignatureRow[0] = "Media";

                             digitalSignatureRow[1] = cabId;

-                            digitalSignatureRow[2] = cert2.Thumbprint;

+                            digitalSignatureRow[2] = certId;

                        }

                     }

                 }

 

The patch reads the existing certificates from the MsiDigitalCertificate
table and reuses them when inscribing the certificates for the signed
medias. Additionally it does not use the certificates thumbprint as an
identifier anymore. 

A reference to the System.Security assembly is required for using the
SignedCms class.

 

I've noted another problem with the inscriber. If the tables
MsiDigitalSignature and/or MsiDigitalCertificate does not exist previously
in the MSI database, importing them will not create the validation rows in
the _Validation table. I don't know if this is a problem or how to add
those. I've included <EnsureTable> elements in my installer, which will
create all validation entries.

 

Kind regards,

Georg von Kries

 

------------------------------------------------------------------------------
See everything from the browser to the database with AppDynamics
Get end-to-end visibility with application monitoring from AppDynamics
Isolate bottlenecks and diagnose root cause in seconds.
Start your free trial of AppDynamics Pro today!
http://pubads.g.doubleclick.net/gampad/clk?id=48808831&iu=/4140/ostg.clktrk
_______________________________________________
WiX-devs mailing list
WiX-devs@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/wix-devs

Reply via email to