Hi,

 

I've created a small bug fix, but the posting needed moderation because it
was too large.

 

I think the identifier gets too long, so I've used an Guid prefixed with
cer. Here are my changes:

 

@@ -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;

                        }

                     }

                 }

 

Kind regards,

Georg von Kries

 

Von: Hoover, Jacob [mailto:[email protected]] 
Gesendet: Dienstag, 9. Juli 2013 19:58
An: Windows Installer XML toolset developer mailing list
Betreff: [WiX-devs] SFBUG: 3341/3340

 

When looking at SFBUG 3340 and 3341,  I attempted to prefix the identifier.
Any time I use anything other than the hash it fails to import.  I've tried
multiple variations (_, cer, Z, etc) of a prefix.  Each time I have verified
that the certificate name in the IDT matches that of the file on disk in the
MsiDigitalCertificate sub folder.  I've tried it with only changing the
identifier and with changing both the identifier and the file name.

 

By chance is there something mis-documented on either the table definition
or the MsiDatabaseImport function? (Is there a reason we are using this
instead of using the DB functions directly?)

 

It may be worth mentioning that I can't even adjust this value with Orca. It
fails on commit with "The data was rejected by the database. It may be out
of the valid range or formatted incorrectly".  I can modify the identifier
in the MsiDigitalSignature table, and I can modify another record in the
MsiDigitalCertificate table. (I have a local fix that leaves the named key
from the MsiPatchCertificate table in place.)  The only other unique thing I
can think of is both certs are identical.

 

Thanks,

Jacob 

 

------------------------------------------------------------------------------
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/wix-devs

Reply via email to