我希望使用本地系统上私钥不可用的证书对HLKX文件进行签名。
我根据“加密提供程序开发工具包”中的KSPs代码示例创建了一个自定义密钥存储提供者(基本上是用于测试目的的shell ),并且我能够注册它,它显示在系统上可用的KSPs的枚举中。
我正在使用符号函数,在一个https://learn.microsoft.com/en-us/windows-hardware/test/hlk/user/hlk-signing-with-an-hsm应用程序中,它是一个示例: C#。
自定义KSP dll应该处理所有符号命令,并连接到后端,该后端允许使用私钥,私钥存储在另一个软件层后面的HSM中,该软件层限制了某些用户对密钥的访问。
当我运行应用程序时,由于缺少私钥,签名失败。因此,我需要以某种方式将证书(是文件中的证书或导入到系统的证书存储区)链接到KSP,导致签名哈希等的调用最终出现在KSP的API中,但我找不到任何关于如何将对KSP的引用添加到C#签名调用的适当信息,或者( b)将证书导入证书存储区,其中引用KSP,以便在使用证书进行签名时自动使用证书。
那么,我怎样才能做到( a)或( b),或者有什么其他的方法来手动处理这个问题?签名应用程序只是使用C#,因为这是我可以从微软找到的这个用例的唯一示例。如果在C/C++中有一个样本,那也会很好。我想在使用CSP而不是KSP的情况下,问题也是一样的,但不幸的是,许多帖子都在大量混合这两种情况。
发布于 2022-08-17 11:36:12
我找到了一种在存储中的证书与提供程序dll之间创建链接的方法(通过在系统中注册提供程序dll的名称)。相应的系统API函数是Crypt32.dll中的CertSetCertificateContextProperty和CertGetCertificateContextProperty。我能够验证这是否适用于hlkx文件的签名(使用硬件Lab软件或通过使用C#代码使用PackageDigitalSignatureManager),但我在使用这种方式签名时仍然有问题,例如使用微软的signtool.exe的可执行文件,它抱怨证书不可用的私钥。
我在C#中使用system函数,因此我从我的项目中提取了有关如何将证书与提供程序链接以及如何从证书中读取链接提供者的信息的相关代码片段。
class Program
{
private const UInt32 CERT_SET_KEY_CONTEXT_PROP_ID = 0x00000001;
private const UInt32 CERT_SET_KEY_PROV_HANDLE_PROP_ID = 0x00000001;
private const UInt32 CERT_KEY_PROV_INFO_PROP_ID = 2;
static void Main(string[] args)
{
// Reading certificate from file
X509Certificate2 certificate = new X509Certificate2("C:\\MyCert.crt");
// Adding certificate to store
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
store.Close();
// Linking certificate with provider
// ProviderName is the name under which the provider is registered in the system
// ContainerName is a string that will be passed to the DLL when calls are made it can be used to
// additional information to the DLL that can be set when linking the certificate with the provider
SetCertificateProviderInformation("My Provider Name", "MyContainerName", certificate);
// Read provider information
GetCertificateProviderInformation(certificate);
}
private static void SetCertificateProviderInformation(string providerName, string containerName, X509Certificate2 certificate)
{
Crypt32Dll.CRYPT_KEY_PROV_INFO cryptKeyProvInfo = new Crypt32Dll.CRYPT_KEY_PROV_INFO
{
pwszProvName = providerName,
pwszContainerName = containerName,
dwProvType = 24,
dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID | CERT_SET_KEY_PROV_HANDLE_PROP_ID,
cProvParam = 0,
rgProvParam = IntPtr.Zero,
dwKeySpec = 2
};
IntPtr pvData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Crypt32Dll.CRYPT_KEY_PROV_INFO)));
Marshal.StructureToPtr(cryptKeyProvInfo, pvData, false);
if (Crypt32Dll.CertSetCertificateContextProperty(certificate.Handle, CERT_KEY_PROV_INFO_PROP_ID, 0, pvData))
{
// succeeded
}
else
{
Int32 lastError = Marshal.GetLastWin32Error();
// failed
}
if (pvData != IntPtr.Zero)
{
Marshal.FreeHGlobal(pvData);
}
}
private static void GetCertificateProviderInformation(X509Certificate2 certificate)
{
UInt32 dataSize = 0;
// Get required size for struct
if (Crypt32Dll.CertGetCertificateContextProperty(certificate.Handle, CERT_KEY_PROV_INFO_PROP_ID, IntPtr.Zero, ref dataSize))
{
// Allocate unmanaged struct memory of required size and query the information
IntPtr pvData = Marshal.AllocHGlobal((int)dataSize);
if (Crypt32Dll.CertGetCertificateContextProperty(certificate.Handle, CERT_KEY_PROV_INFO_PROP_ID, pvData, ref dataSize))
{
// succeeded
Crypt32Dll.CRYPT_KEY_PROV_INFO keyProviderInformation = (Crypt32Dll.CRYPT_KEY_PROV_INFO)Marshal.PtrToStructure(pvData, typeof(Crypt32Dll.CRYPT_KEY_PROV_INFO));
Console.Out.WriteLine("Provider Name: " + keyProviderInformation.pwszProvName);
Console.Out.WriteLine("Container Name: " + keyProviderInformation.pwszContainerName);
}
else
{
int lastError = Marshal.GetLastWin32Error();
// failed
}
// Free unmanaged struct memory
Marshal.FreeHGlobal(pvData);
}
else
{
// failed
}
}
}使用Crypt32.dll的代码为:
class Crypt32Dll
{
private const string DLL_NAME = "Crypt32.dll";
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct CRYPT_KEY_PROV_INFO
{
[MarshalAs(UnmanagedType.LPWStr)]
internal string pwszContainerName;
[MarshalAs(UnmanagedType.LPWStr)]
internal string pwszProvName;
internal UInt32 dwProvType;
internal UInt32 dwFlags;
internal UInt32 cProvParam;
internal IntPtr rgProvParam;
internal UInt32 dwKeySpec;
}
[DllImport(DLL_NAME, EntryPoint = "CertSetCertificateContextProperty", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool CertSetCertificateContextProperty(
IntPtr pCertContext,
UInt32 dwPropId,
UInt32 dwFlags,
IntPtr pvData
);
[DllImport(DLL_NAME, EntryPoint = "CertGetCertificateContextProperty", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool CertGetCertificateContextProperty(
IntPtr pCertContext,
UInt32 dwPropId,
IntPtr pvData,
ref UInt32 pcbData
);
}https://stackoverflow.com/questions/72982683
复制相似问题