Search code examples
c#winapicryptographycatalog

get "thumbprint" value of security catalog tag from .cat file


I want to compare the hashes for every tag of 2 Security Catalog (.cat) files.

I get all tags with the CryptCATEnumerateMember function and tried to get the hashes with CryptCATEnumerateAttr, but this didn't work.

IntPtr pMemberPtr = CatalogFunctions.CryptCATEnumerateMember(hCatalog, IntPtr.Zero);            
            while (pMemberPtr != IntPtr.Zero)
            {
                CRYPTCATMEMBER cdf = (CRYPTCATMEMBER)Marshal.PtrToStructure(pMemberPtr, typeof(CRYPTCATMEMBER));
                IntPtr pAttributePtr = CatalogFunctions.CryptCATEnumerateAttr(hCatalog, pMemberPtr, IntPtr.Zero);
                while (pAttributePtr != IntPtr.Zero)
                {
                    CRYPTCATATTRIBUTE cdfa = (CRYPTCATATTRIBUTE)Marshal.PtrToStructure(pAttributePtr, typeof(CRYPTCATATTRIBUTE));
                    data.Add(cdfa.cbValue.ToString());
                    pAttributePtr = CatalogFunctions.CryptCATEnumerateAttr(hCatalog, pMemberPtr, pAttributePtr);
                }
                data.Add(cdf.pwszReferenceTag);
                pMemberPtr = CatalogFunctions.CryptCATEnumerateMember(hCatalog, pMemberPtr);
            }
//with the functions and classes:
        [DllImport("Wintrust.dll")]
        public static extern unsafe IntPtr CryptCATEnumerateMember(
            IntPtr hCatalog,
            IntPtr pPrevMember); 
        [DllImport("Wintrust.dll")]
        public static extern unsafe IntPtr CryptCATEnumerateAttr(
            IntPtr hCatalog,
            IntPtr pCatMember,
            IntPtr pPrevAttr);

    [StructLayout(LayoutKind.Sequential)]
    public class CRYPTCATATTRIBUTE {
        public uint cbStruct;
        public string pwszReferenceTag;
        public uint dwAttrTypeAndAction;
        public uint cbValue;                        
        public unsafe byte* pdValue;                
        public uint dwReserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    public class CRYPTCATMEMBER
    {
        public uint cbStruct;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwszReferenceTag;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwszFileName;
        public GUID gSubjectType;
        public uint fdwMemberFlags;
        public IntPtr pIndirectData;
        public uint dwCertVersion;
        public uint dwReserved;
        public IntPtr hReserved;
        public CRYPTOAPI_BLOB sEncodedIndirectData;
        public CRYPTOAPI_BLOB sEncodedMemberInfo;
    }

the project compiles, but pAttributePtr allways points to 0.


Solution

  • This works for me (tested on Windows 10, VS 2015, with C:\Program Files\USBPcap\usbpcapamd64.cat file =>

     public partial class Form1 : Form
        {
            [DllImport("Wintrust.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern IntPtr CryptCATOpen(string pwszFileName, int fdwOpenFlags, IntPtr hProv, int dwPublicVersion, int dwEncodingType);
    
            [DllImport("Wintrust.dll", SetLastError = true)]
            public static extern bool CryptCATClose(IntPtr hCatalog);
    
            [DllImport("Wintrust.dll", SetLastError = true)]
            public static extern IntPtr CryptCATEnumerateMember(IntPtr hCatalog, IntPtr pPrevMember);
    
            [DllImport("Wintrust.dll", SetLastError = true)]
            public static extern IntPtr CryptCATEnumerateAttr(IntPtr hCatalog, IntPtr pCatMember, IntPtr pPrevAttr);
    
            public const int INVALID_HANDLE_VALUE = -1;
    
            [StructLayout(LayoutKind.Sequential)]
            public struct CRYPTCATMEMBER
            {
                public int  cbStruct;           // = sizeof(CRYPTCATMEMBER)
                public IntPtr pwszReferenceTag;
                public IntPtr pwszFileName;       // used only by the CDF APIs
                public Guid gSubjectType;       // may be zeros -- see sEncodedMemberInfo
                public int fdwMemberFlags;
                public IntPtr pIndirectData;     // may be null -- see sEncodedIndirectData
                public int dwCertVersion;      // may be zero -- see sEncodedMemberInfo
                public int dwReserved;         // used by enum -- DO NOT USE!
                public IntPtr hReserved;          // pStack(attrs) (null if init) INTERNAL!
    
                public CRYPT_ATTR_BLOB sEncodedIndirectData;   // lazy decode
                public CRYPT_ATTR_BLOB sEncodedMemberInfo;     // lazy decode
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct CRYPT_ATTR_BLOB
            {
                public int cbData;
                public IntPtr pbData;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct SIP_INDIRECT_DATA
            {
                public CRYPT_ATTRIBUTE_TYPE_VALUE Data;            // Encoded attribute
                public CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm; // Digest algorithm used to hash
                public CRYPT_HASH_BLOB Digest;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct CRYPT_ALGORITHM_IDENTIFIER
            {
                public IntPtr pszObjId;
                public CRYPT_OBJID_BLOB Parameters;
            }     
    
            [StructLayout(LayoutKind.Sequential)]
            public struct CRYPT_ATTRIBUTE_TYPE_VALUE
            {
                public IntPtr pszObjId;
                public CRYPT_OBJID_BLOB Value;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct CRYPT_OBJID_BLOB
            {
                public int cbData;
                public IntPtr pbData;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct CRYPT_HASH_BLOB
            {
                public int cbData;
                public IntPtr pbData;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct CRYPTCATATTRIBUTE
            {
                public int cbStruct;           // = sizeof(CRYPTCATATTRIBUTE)
                public IntPtr pwszReferenceTag;
                public int dwAttrTypeAndAction;
                public int cbValue;
                public IntPtr pbValue;           // encoded CAT_NAMEVALUE struct
                public int dwReserved;         // used by enum -- DO NOT USE!
            }  
    
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                IntPtr hCatalog = CryptCATOpen("C:\\Program Files\\USBPcap\\usbpcapamd64.cat", 0, IntPtr.Zero, 0, 0);
                if (hCatalog != (IntPtr)INVALID_HANDLE_VALUE)
                {
                    IntPtr pMember = IntPtr.Zero;               
                    while ((pMember = CryptCATEnumerateMember(hCatalog, pMember)) != IntPtr.Zero)
                    {
                        CRYPTCATMEMBER pCRYPTCATMEMBER = (CRYPTCATMEMBER)Marshal.PtrToStructure(pMember, typeof(CRYPTCATMEMBER));
                        SIP_INDIRECT_DATA pSIP_INDIRECT_DATA = (SIP_INDIRECT_DATA)Marshal.PtrToStructure(pCRYPTCATMEMBER.pIndirectData, typeof(SIP_INDIRECT_DATA));
    
                        StringBuilder sbData = new StringBuilder();
                        IntPtr pData = pSIP_INDIRECT_DATA.Digest.pbData;
                        for (int i = 0; i < pSIP_INDIRECT_DATA.Digest.cbData; i++)
                        {
                            byte byteValue = Marshal.ReadByte(pData);
                            sbData.Append(string.Format("{0:X}", byteValue));
                            pData += 1;
                        }
                        Console.WriteLine("Data = " + sbData.ToString());
    
                        IntPtr pAttr = IntPtr.Zero;
                        while ((pAttr = CryptCATEnumerateAttr(hCatalog, pMember, pAttr)) != IntPtr.Zero)
                        {
                            CRYPTCATATTRIBUTE pCRYPTCATATTRIBUTE = (CRYPTCATATTRIBUTE)Marshal.PtrToStructure(pAttr, typeof(CRYPTCATATTRIBUTE));                      
                            string sReferenceTag = Marshal.PtrToStringUni(pCRYPTCATATTRIBUTE.pwszReferenceTag);
                            Console.WriteLine("\tReferenceTag = " + sReferenceTag);
                            StringBuilder sbValue = new StringBuilder();
                            IntPtr pValue = pCRYPTCATATTRIBUTE.pbValue;
                            for (int i = 0; i < pCRYPTCATATTRIBUTE.cbValue; i++)
                            {
                                byte byteValue = Marshal.ReadByte(pValue);
                                sbValue.Append(string.Format("{0:X}", byteValue));
                                pValue += 1;
                            }
                            Console.WriteLine("\tValue = " + sbValue.ToString());
                        }                   
                    }
                    CryptCATClose(hCatalog);
                }
                else throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }