Hi all,
Some time ago I posted the following sample How to call CryptMsg API in streaming mode (C#).Well, I continued working on that CryptMsg sample, and I got many consts, structs and API declarations that may help you if you need to p/invoke CryptoAPI in C#. You may also want to check this other post of mine: P/Invoking CryptoAPI in .NET (C# version), to see more CryptoAPI declarations.
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using System.ComponentModel; using System.Security.Cryptography; namespace LargeCMS { partial class Win32 { #region "CONSTS" internal const int X509_ASN_ENCODING = 0x00000001; internal const int PKCS_7_ASN_ENCODING = 0x00010000; internal const int CMSG_SIGNED = 2; internal const int CMSG_ENVELOPED = 3; internal const int CMSG_DETACHED_FLAG = 0x00000004; internal const int CMSG_AUTHENTICATED_ATTRIBUTES_FLAG = 0x00000008; internal const int CMSG_ENVELOPE_ALGORITHM_PARAM = 15; internal const int CMSG_ENCODED_SIGNER = 8; internal const int CMSG_ENCODED_MESSAGE = 29; internal const int CMSG_CTRL_VERIFY_SIGNATURE = 1; internal const int CMSG_CTRL_DECRYPT = 2; internal const int CMSG_CTRL_VERIFY_SIGNATURE_EX = 19; internal const int CMSG_CTRL_ADD_SIGNER = 6; internal const int CMSG_CTRL_ADD_CERT = 10; internal const int CMSG_SIGNER_COUNT_PARAM = 5; internal const int CMSG_SIGNER_INFO_PARAM = 6; internal const int CMSG_SIGNER_CERT_INFO_PARAM = 7; internal const int CMSG_CERT_COUNT_PARAM = 11; internal const int CMSG_CERT_PARAM = 12; internal const int CMSG_RECIPIENT_COUNT_PARAM = 17; internal const int CMSG_RECIPIENT_INFO_PARAM = 19; internal const int CMSG_VERIFY_SIGNER_CERT = 2; internal const int CMSG_RC4_NO_SALT_FLAG = 0x40000000; internal const int AT_KEYEXCHANGE = 1; internal const int AT_SIGNATURE = 2; internal const String szOID_OIWSEC_rsaSign = "1.3.14.3.2.11"; internal const String szOID_OIWSEC_shaRSA = "1.3.14.3.2.15"; internal const String szOID_OIWSEC_sha = "1.3.14.3.2.18"; internal const String szOID_OIWSEC_sha1 = "1.3.14.3.2.26"; internal const String szOID_OIWSEC_sha1RSASign = "1.3.14.3.2.29"; internal const String szOID_RSA_RC4 = "1.2.840.113549.3.4"; internal const String szOID_RSA_DES_EDE3_CBC = "1.2.840.113549.3.7"; internal const String szOID_RSA_signingTime = "1.2.840.113549.1.9.5"; internal const int X509_NAME = 7; internal const int CERT_STORE_PROV_MSG = 1; internal const int CERT_CLOSE_STORE_FORCE_FLAG = 1; internal const int CERT_KEY_PROV_INFO_PROP_ID = 2; internal const int CERT_STORE_PROV_SYSTEM = 10; internal const int CERT_SYSTEM_STORE_CURRENT_USER = 1 << 16; #endregion #region "STRUCTS" [StructLayout(LayoutKind.Sequential)] internal struct CRYPT_ALGORITHM_IDENTIFIER { public string pszObjId; public BLOB Parameters; public void Dispose() { Parameters.Dispose(); } } [StructLayout(LayoutKind.Sequential)] internal struct CERT_ID { public int dwIdChoice; public BLOB IssuerSerialNumberOrKeyIdOrHashId; } [StructLayout(LayoutKind.Sequential)] internal struct CRYPT_ATTRIBUTE { public string pszObjId; public int cValue; public IntPtr rgValue; public void Dispose() { if (!rgValue.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgValue); } } } [StructLayout(LayoutKind.Sequential)] internal struct CMSG_SIGNER_ENCODE_INFO { public int cbSize; public IntPtr pCertInfo; public IntPtr hCryptProvOrhNCryptKey; public int dwKeySpec; public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm; public IntPtr pvHashAuxInfo; public int cAuthAttr; public IntPtr rgAuthAttr; public int cUnauthAttr; public IntPtr rgUnauthAttr; public CERT_ID SignerId; public CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm; public IntPtr pvHashEncryptionAuxInfo; public void Dispose() { if (!hCryptProvOrhNCryptKey.Equals(IntPtr.Zero)) { Win32.CryptReleaseContext(hCryptProvOrhNCryptKey, 0); } if (!rgAuthAttr.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgAuthAttr); } if (!rgUnauthAttr.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgUnauthAttr); } } } [StructLayout(LayoutKind.Sequential)] internal struct CERT_CONTEXT { public int dwCertEncodingType; public IntPtr pbCertEncoded; public int cbCertEncoded; public IntPtr pCertInfo; public IntPtr hCertStore; } [StructLayout(LayoutKind.Sequential)] internal struct BLOB { public int cbData; public IntPtr pbData; public void Dispose() { if (!pbData.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(pbData); } } } [StructLayout(LayoutKind.Sequential)] internal struct CRYPT_BIT_BLOB { public int cbData; public IntPtr pbData; public int cUnusedBits; } [StructLayout(LayoutKind.Sequential)] internal struct CMSG_SIGNED_ENCODE_INFO { public int cbSize; public int cSigners; public IntPtr rgSigners; public int cCertEncoded; public IntPtr rgCertEncoded; public int cCrlEncoded; public IntPtr rgCrlEncoded; public int cAttrCertEncoded; public IntPtr rgAttrCertEncoded; public void Dispose() { if (!rgSigners.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgSigners); } if (!rgCertEncoded.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgCertEncoded); } if (!rgCrlEncoded.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgCrlEncoded); } if (!rgAttrCertEncoded.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgAttrCertEncoded); } } } [StructLayout(LayoutKind.Sequential)] internal struct CRYPT_ATTRIBUTES { public int cAttr; public IntPtr rgAttr; } [StructLayout(LayoutKind.Sequential)] internal struct CMSG_SIGNER_INFO { public int dwVersion; public BLOB Issuer; public BLOB SerialNumber; public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm; public CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm; public BLOB EncryptedHash; public CRYPT_ATTRIBUTES AuthAttrs; public CRYPT_ATTRIBUTES UnauthAttrs; } [StructLayout(LayoutKind.Sequential)] internal struct CMSG_STREAM_INFO { public int cbContent; public StreamOutputCallbackDelegate pfnStreamOutput; public IntPtr pvArg; } [StructLayout(LayoutKind.Sequential)] internal struct CERT_PUBLIC_KEY_INFO { public CRYPT_ALGORITHM_IDENTIFIER Algorithm; public CRYPT_BIT_BLOB PublicKey; } [StructLayout(LayoutKind.Sequential)] internal struct FILETIME { public int dwLowDateTime; public int dwHighDateTime; } [StructLayout(LayoutKind.Sequential)] internal struct CERT_INFO { public int dwVersion; public BLOB SerialNumber; public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm; public BLOB Issuer; public FILETIME NotBefore; public FILETIME NotAfter; public BLOB Subject; public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo; public CRYPT_BIT_BLOB IssuerUniqueId; public CRYPT_BIT_BLOB SubjectUniqueId; public int cExtension; public IntPtr rgExtension; } [StructLayout(LayoutKind.Sequential)] internal struct CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA { public int cbSize; public IntPtr hCryptProv; public int dwSignerIndex; public int dwSignerType; public IntPtr pvSigner; } [StructLayout(LayoutKind.Sequential)] internal struct CMSG_ENVELOPED_ENCODE_INFO { public int cbSize; public IntPtr hCryptProv; public CRYPT_ALGORITHM_IDENTIFIER ContentEncryptionAlgorithm; public IntPtr pvEncryptionAuxInfo; public int cRecipients; public IntPtr rgpRecipients; public IntPtr rgCmsRecipients; public int cCertEncoded; public IntPtr rgCertEncoded; public int cCrlEncoded; public IntPtr rgCrlEncoded; public int cAttrCertEncoded; public IntPtr rgAttrCertEncoded; public int cUnprotectedAttr; public IntPtr rgUnprotectedAttr; public void Dispose() { ContentEncryptionAlgorithm.Dispose(); if (!pvEncryptionAuxInfo.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(pvEncryptionAuxInfo); } if (!rgpRecipients.Equals(IntPtr.Zero)) { Marshal.FreeHGlobal(rgpRecipients); } } } [StructLayout(LayoutKind.Sequential)] internal struct CMSG_RC4_AUX_INFO { public int cbSize; public int dwBitLen; } [StructLayout(LayoutKind.Sequential)] internal struct CMSG_CTRL_DECRYPT_PARA { public int cbSize; public IntPtr hCryptProvOrNCryptKey; public int dwKeySpec; public int dwRecipientIndex; } [StructLayout(LayoutKind.Sequential)] internal struct CRYPT_KEY_PROV_INFO { [MarshalAs(UnmanagedType.LPWStr)]public string pwszContainerName; [MarshalAs(UnmanagedType.LPWStr)]public string pwszProvName; public int dwProvType; public int dwFlags; public int cProvParam; public IntPtr rgProvParam; public int dwKeySpec; } #endregion #region "DELEGATES" internal delegate Boolean StreamOutputCallbackDelegate(IntPtr pvArg, IntPtr pbData, int cbData, Boolean fFinal); #endregion #region "API" [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] internal static extern Boolean CryptAcquireContext( out SafeCSPHandle hProv, string pszContainer, string pszProvider, int dwProvType, int dwFlags ); [DllImport("crypt32.dll", CharSet = CharSet.Ansi, SetLastError = true)] internal static extern bool CryptEncodeObject( int dwCertEncodingType, string lpszStructType, ref long pvStructInfo, SafeNTHeapHandle pbEncoded, ref int pcbEncoded ); [DllImport("crypt32.dll", CharSet = CharSet.Ansi, SetLastError = true)] internal static extern Boolean CryptDecodeObject( int dwCertEncodingType, string lpszStructType, IntPtr pbEncoded, int cbEncoded, int dwFlags, out long pvStructInfo, ref int pcbStructInfo ); [DllImport("crypt32.dll", CharSet = CharSet.Ansi, SetLastError = true)] internal static extern Boolean CryptDecodeObject( int dwCertEncodingType, int lpszStructType, IntPtr pbEncoded, int cbEncoded, int dwFlags, StringBuilder pvStructInfo, ref int pcbStructInfo ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern SafeMsgHandle CryptMsgOpenToEncode( int dwMsgEncodingType, int dwFlags, int dwMsgType, ref CMSG_SIGNED_ENCODE_INFO pvMsgEncodeInfo, string pszInnerContentObjID, ref CMSG_STREAM_INFO pStreamInfo ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern SafeMsgHandle CryptMsgOpenToEncode( int dwMsgEncodingType, int dwFlags, int dwMsgType, ref CMSG_ENVELOPED_ENCODE_INFO pvMsgEncodeInfo, string pszInnerContentObjID, ref CMSG_STREAM_INFO pStreamInfo ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern SafeMsgHandle CryptMsgOpenToDecode( int dwMsgEncodingType, int dwFlags, int dwMsgType, IntPtr hCryptProv, IntPtr pRecipientInfo, ref CMSG_STREAM_INFO pStreamInfo ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern SafeMsgHandle CryptMsgOpenToDecode( int dwMsgEncodingType, int dwFlags, int dwMsgType, IntPtr hCryptProv, IntPtr pRecipientInfo, IntPtr pStreamInfo ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern Boolean CryptMsgClose( IntPtr hCryptMsg ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern Boolean CryptMsgUpdate( IntPtr hCryptMsg, Byte[] pbData, int cbData, Boolean fFinal ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern Boolean CryptMsgUpdate( IntPtr hCryptMsg, IntPtr pbData, int cbData, Boolean fFinal ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern Boolean CryptMsgGetParam( SafeMsgHandle hCryptMsg, int dwParamType, int dwIndex, SafeNTHeapHandle pvData, ref int pcbData ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern Boolean CryptMsgGetParam( SafeMsgHandle hCryptMsg, int dwParamType, int dwIndex, out int pvData, ref int pcbData ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern Boolean CryptMsgControl( SafeMsgHandle hCryptMsg, int dwFlags, int dwCtrlType, IntPtr pvCtrlPara ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern Boolean CryptMsgControl( SafeMsgHandle hCryptMsg, int dwFlags, int dwCtrlType, ref CMSG_SIGNER_ENCODE_INFO pvCtrlPara ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern Boolean CryptMsgControl( SafeMsgHandle hCryptMsg, int dwFlags, int dwCtrlType, ref BLOB pvCtrlPara ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern Boolean CryptMsgControl( SafeMsgHandle hCryptMsg, int dwFlags, int dwCtrlType, ref CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA pvCtrlPara ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern Boolean CryptMsgControl( SafeMsgHandle hCryptMsg, int dwFlags, int dwCtrlType, ref CMSG_CTRL_DECRYPT_PARA pvCtrlPara ); [DllImport("advapi32.dll", SetLastError = true)] internal static extern Boolean CryptReleaseContext( IntPtr hProv, int dwFlags ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern SafeCertContextHandle CertCreateCertificateContext( int dwCertEncodingType, SafeNTHeapHandle pbCertEncoded, int cbCertEncoded ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern Boolean CertFreeCertificateContext( IntPtr pCertContext ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern SafeStoreHandle CertOpenStore( int lpszStoreProvider, int dwMsgAndCertEncodingType, IntPtr hCryptProv, int dwFlags, SafeMsgHandle pvPara ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern SafeStoreHandle CertOpenSystemStore( IntPtr hprov, string szSubsystemProtocol ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern SafeCertContextHandle CertGetSubjectCertificateFromStore( SafeStoreHandle hCertStore, int dwCertEncodingType, SafeNTHeapHandle pCertId ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern IntPtr CertCloseStore( IntPtr hCertStore, int dwFlags ); [DllImport("Crypt32.dll", SetLastError = true)] internal static extern bool CertGetCertificateContextProperty( SafeCertContextHandle pCertContext, int dwPropId, SafeNTHeapHandle pvData, ref int pcbData ); [DllImport("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)] internal static extern IntPtr MemSet( IntPtr ptr, int value, int num ); #endregion } }
I hope this helps.
Regards,
Alex (Alejandro Campos Magencio)
Hi Alejandro,
Would you kindly present a solution, where you can retrieve certain attributes of signed executable using P/Invoking. I'm particulary interested how to retrieve Countersignature TimeStamp property and convert it to DateTime object using C#.
Thanks.
Hi Martin,
I would love to do that, but that is out of the scope of this blog. Have you checked this post of mine, where I do all kind of things with these APIs?
How to call CryptMsg API in streaming mode - LargeCMS full sample
blogs.msdn.com/.../how-to-call-cryptmsgapi-in-streaming-mode-largecms-full-sample.aspx
I hope that helps. If not, you may open a support case with us so we can assist you with that task.
Alex