3

I have a signed "DLL" file that I want to validate his digital signature in run time ("Before I'm loading it")

I have the public key of the certificate embedded in my code, Is there a way to get the "message digest" from the digital signature? or another way to validate the file hasn't manipulated?

I don't want to check the "CA" and other attributes of the certificate because a malicious user can create a certificate with the same attributes

*Note I don't want to user SignTool as well :)

3
  • it is possible, but through p/invoke and CryptoAPI unmanaged functions. You need to call CryptQueryObject function to get PKCS#7 object, then call CryptGetMsgParam to extract raw signature. And then use SignedCms .NET class to access managed signature. Commented Jun 1, 2015 at 10:52
  • Hi @CryptoGuy, can you give me an example code for that? Thanks Commented Jun 1, 2015 at 12:43
  • 1
    Probably, yes. Later. Commented Jun 1, 2015 at 13:41

1 Answer 1

6

There is some job for CryptoAPI and p/invoke (I don't know how to extract authenticode signature with .NET). Here is a code example of what I meant in my comment:

using System; using System.ComponentModel; using System.Runtime.InteropServices; using System.Security.Cryptography.Pkcs; namespace CLRSignatures { class Program { static void Main(string[] args) { IntPtr phCertStore = IntPtr.Zero; IntPtr phMsg = IntPtr.Zero; IntPtr ppvContext = IntPtr.Zero; int pdwMsgAndCertEncodingType = 0; int pdwContentType = 0; int pdwFormatType = 0; if (!Crypt32.CryptQueryObject( Wincrypt.CERT_QUERY_OBJECT_FILE, args[0], Wincrypt.CERT_QUERY_CONTENT_FLAG_ALL, Wincrypt.CERT_QUERY_FORMAT_FLAG_ALL, 0, ref pdwMsgAndCertEncodingType, ref pdwContentType, ref pdwFormatType, ref phCertStore, ref phMsg, ref ppvContext )) { Console.WriteLine((new Win32Exception(Marshal.GetLastWin32Error())).Message); return; } int pcbData = 0; if (!Crypt32.CryptMsgGetParam(phMsg, Wincrypt.CMSG_ENCODED_MESSAGE, 0, null, ref pcbData)) { Console.WriteLine((new Win32Exception(Marshal.GetLastWin32Error())).Message); return; } byte[] pvData = new byte[pcbData]; Crypt32.CryptMsgGetParam(phMsg, Wincrypt.CMSG_ENCODED_MESSAGE, 0, pvData, ref pcbData); var signedCms = new SignedCms(); signedCms.Decode(pvData); try { signedCms.CheckSignature(false); Console.WriteLine("Signature check passed"); } catch (Exception e) { Console.WriteLine(e.Message); } finally { Crypt32.CryptMsgClose(phMsg); Crypt32.CertCloseStore(phCertStore, 0); } } } static class Wincrypt { // source type public const int CERT_QUERY_OBJECT_FILE = 1; // object type const int CERT_QUERY_CONTENT_CERT = 1; const int CERT_QUERY_CONTENT_CTL = 2; const int CERT_QUERY_CONTENT_CRL = 3; const int CERT_QUERY_CONTENT_SERIALIZED_STORE = 4; const int CERT_QUERY_CONTENT_SERIALIZED_CERT = 5; const int CERT_QUERY_CONTENT_SERIALIZED_CTL = 6; const int CERT_QUERY_CONTENT_SERIALIZED_CRL = 7; const int CERT_QUERY_CONTENT_PKCS7_SIGNED = 8; const int CERT_QUERY_CONTENT_PKCS7_UNSIGNED = 9; const int CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED = 10; const int CERT_QUERY_CONTENT_PKCS10 = 11; const int CERT_QUERY_CONTENT_PFX = 12; const int CERT_QUERY_CONTENT_CERT_PAIR = 13; const int CERT_QUERY_CONTENT_FLAG_CERT = (1 << CERT_QUERY_CONTENT_CERT); const int CERT_QUERY_CONTENT_FLAG_CTL = (1 << CERT_QUERY_CONTENT_CTL); const int CERT_QUERY_CONTENT_FLAG_CRL = (1 << CERT_QUERY_CONTENT_CRL); const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE = (1 << CERT_QUERY_CONTENT_SERIALIZED_STORE); const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT = (1 << CERT_QUERY_CONTENT_SERIALIZED_CERT); const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL = (1 << CERT_QUERY_CONTENT_SERIALIZED_CTL); const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL = (1 << CERT_QUERY_CONTENT_SERIALIZED_CRL); const int CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED = (1 << CERT_QUERY_CONTENT_PKCS7_SIGNED); const int CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED = (1 << CERT_QUERY_CONTENT_PKCS7_UNSIGNED); const int CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED = (1 << CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED); const int CERT_QUERY_CONTENT_FLAG_PKCS10 = (1 << CERT_QUERY_CONTENT_PKCS10); const int CERT_QUERY_CONTENT_FLAG_PFX = (1 << CERT_QUERY_CONTENT_PFX); const int CERT_QUERY_CONTENT_FLAG_CERT_PAIR = (1 << CERT_QUERY_CONTENT_CERT_PAIR); public const int CERT_QUERY_CONTENT_FLAG_ALL = CERT_QUERY_CONTENT_FLAG_CERT | CERT_QUERY_CONTENT_FLAG_CTL | CERT_QUERY_CONTENT_FLAG_CRL | CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE | CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT | CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL | CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL | CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED | CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED | CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX | CERT_QUERY_CONTENT_FLAG_CERT_PAIR; // format type const int CERT_QUERY_FORMAT_BINARY = 1; const int CERT_QUERY_FORMAT_BASE64_ENCODED = 2; const int CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED = 3; const int CERT_QUERY_FORMAT_FLAG_BINARY = 1 << CERT_QUERY_FORMAT_BINARY; const int CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED = 1 << CERT_QUERY_FORMAT_BASE64_ENCODED; const int CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED = 1 << CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED; public const int CERT_QUERY_FORMAT_FLAG_ALL = CERT_QUERY_FORMAT_FLAG_BINARY | CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED | CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED; public const int CMSG_ENCODED_MESSAGE = 29; } static class Crypt32 { [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool CryptQueryObject( int dwObjectType, [MarshalAs(UnmanagedType.LPWStr)] string pvObject, int dwExpectedContentTypeFlags, int dwExpectedFormatTypeFlags, int dwFlags, ref int pdwMsgAndCertEncodingType, ref int pdwContentType, ref int pdwFormatType, ref IntPtr phCertStore, ref IntPtr phMsg, ref IntPtr ppvContext ); [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool CryptMsgGetParam( IntPtr hCryptMsg, int dwParamType, int dwIndex, byte[] pvData, ref int pcbData ); [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool CryptMsgClose( IntPtr hCryptMsg ); [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool CertCloseStore( IntPtr hCertStore, int dwFlags ); } } 

p.s. note that you have to reference System.Security assembly. args[0] receives the path to a DLL file.

Sign up to request clarification or add additional context in comments.

10 Comments

Thank you very much! , But I want for example instead of: "signedCms.CheckSignature(false);" to check it with external public key / X509Certificate2. The "CheckSignature" method with X509Certificate2Collection doesn't seems to do the Job...
You can call CheckSignature(false) on required signature in the SignerInfos property. This property contains an array of signer information including public certificate.
But I want to check it with an external certificat, This certificate is not include in the DLL But has the same public key
I would suggest to use certificates attached to signature, because your certificate may produce different results.
you are incorrect, because private and public keys are strictly associated. Particular public key may have only one associated private key and vice versa. And if malicious user was able to generate signature that is validated with the same public key (as your), then malicious user has your private key. You are hacked.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.