首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将KSP DLL链接到证书

如何将KSP DLL链接到证书
EN

Stack Overflow用户
提问于 2022-07-14 15:02:32
回答 1查看 64关注 0票数 0

我希望使用本地系统上私钥不可用的证书对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的情况下,问题也是一样的,但不幸的是,许多帖子都在大量混合这两种情况。

EN

回答 1

Stack Overflow用户

发布于 2022-08-17 11:36:12

我找到了一种在存储中的证书与提供程序dll之间创建链接的方法(通过在系统中注册提供程序dll的名称)。相应的系统API函数是Crypt32.dll中的CertSetCertificateContextProperty和CertGetCertificateContextProperty。我能够验证这是否适用于hlkx文件的签名(使用硬件Lab软件或通过使用C#代码使用PackageDigitalSignatureManager),但我在使用这种方式签名时仍然有问题,例如使用微软的signtool.exe的可执行文件,它抱怨证书不可用的私钥。

我在C#中使用system函数,因此我从我的项目中提取了有关如何将证书与提供程序链接以及如何从证书中读取链接提供者的信息的相关代码片段。

代码语言:javascript
复制
    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的代码为:

代码语言:javascript
复制
    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
        );
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72982683

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档