1

I have a couple of product codes filtered from MsiEnumProducts and need to get their assigned certificates. It should be possible to get the cert by using MsiOpenDatabase, but I don't know how to reliably get paths to the .msi files.

I would prefer to avoid external assemblies (like wix), only pinvoke.

Klocman
  • 432
  • 4
  • 12
  • 2
    I don't think anything in the MSI API does this. Presumably you've already figured out how to get the path to the cached MSI in C:\Windows\Installer. You'll need some other API to inspect the certificate applied to this file. Note that on pre Windows 7 the cert will be invalid because Windows modified the file when it removed the embedded cabs. – Christopher Painter May 23 '15 at 10:51
  • I believe the certificate will also be missing if the install was run from an [**admin image**](http://stackoverflow.com/questions/1547809/extract-msi-from-exe/24987512#24987512) extracted from the original MSI. I am not sure if this affects the MsiDigitalSignature table and its associated tables. Just find a signed MSI file, run an admin image and check the tables. – Stein Åsmul May 23 '15 at 12:44

1 Answers1

2

Given a product code, a call to MsiGetProductInfo passing the property name INSTALLPROPERTY_LOCALPACKAGE returns the location of the cached installer package in C:\Windows\Installer.

Once you have the cached package, a call to MsiGetFileSignatureInformation can retrieve the certificate.

Example using pInvoke:

using System;
using System.Text;
using System.Runtime.InteropServices;

class Program
{
    [DllImport("msi.dll", CharSet = CharSet.Ansi, SetLastError = false)]
    static extern int MsiEnumProducts(int iProductIndex, StringBuilder lpProductBuf);

    [DllImport("msi.dll", CharSet = CharSet.Ansi, SetLastError = false)]
    static extern int MsiGetProductInfo(string product, string property, [Out] StringBuilder valueBuf, ref Int32 len);

    [DllImport("msi.dll", CharSet = CharSet.Ansi, SetLastError = false)]
    static extern int MsiGetFileSignatureInformation(string fileName, int flags, out IntPtr certContext, IntPtr hashData, ref int hashDataLength);

    [DllImport("Crypt32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    static extern int CertFreeCertificateContext( IntPtr certContext );

    [DllImport("Crypt32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    static extern int CertGetNameString(IntPtr certContext, UInt32 type, UInt32 flags, IntPtr typeParameter, StringBuilder stringValue, UInt32 stringLength );

    static void Main(string[] args)
    {
        int index = 0;
        StringBuilder productCode = new StringBuilder();
        int result = MsiEnumProducts(index, productCode);
        while (result == 0)
        {
            Console.WriteLine("{0}", productCode);

            Int32 length = 1024;
            StringBuilder fileName = new StringBuilder();
            result = MsiGetProductInfo(
                        productCode.ToString(),
                        "LocalPackage",
                        fileName,
                        ref length );
            if (result == 0)
            {
                Console.WriteLine("{0}", fileName);

                IntPtr certContext = IntPtr.Zero;
                IntPtr hashData = IntPtr.Zero;
                int hashDataLength = 0;
                result = MsiGetFileSignatureInformation(
                            fileName.ToString(),
                            0,
                            out certContext,
                            hashData,
                            ref hashDataLength);
                if ( result == 0 )
                {
                    Console.WriteLine("Got Cert");

                    StringBuilder simpleDisplayType = new StringBuilder();
                    int ok = CertGetNameString(
                                certContext,
                                4,                      // == CERT_NAME_SIMPLE_DISPLAY_TYPE
                                0,
                                IntPtr.Zero,
                                simpleDisplayType,
                                1024 );
                    if (ok != 0)
                    {
                        Console.WriteLine("{0}", simpleDisplayType);
                    }

                    CertFreeCertificateContext(certContext);
                }
            }

            ++index;
            result = MsiEnumProducts(index, productCode);
        }
    }
}
bradfordrg
  • 1,863
  • 2
  • 21
  • 34