Verifying digital signature in C #
I have a signed "DLL" file that I want to verify its digital signature at runtime ("Before 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 is there another way to check the file not being processed?
I don't want to check "CA" and other attributes of the certificate, because a malicious user can create a certificate with the same attributes
* Note. I also don't want the SignTool user :)
source to share
There is some work around for CryptoAPI and p / invoke (I don't know how to extract the signature signature using .NET). Here is some sample code that I had in mind 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
);
}
}
ps note that you need to reference the assembly System.Security
. args[0]
gets the path to the DLL file.
source to share