2

我想在 Azure Key Vault 的 HSM 中生成一个私钥,然后创建一个证书签名请求 CSR,其中包含相应的公钥。

正在生成公钥,然后是 CSR,甚至可以在今天的 Key Vault 中生成 - 我在文档中没有看到任何关于生成相应公钥的提及?(或者也许我只是不了解 HSM 的本质?)

回退似乎是在其他地方创建密钥和 CSR,并将私钥导入 Key Vault HSM。这显然不如 HSM 之外从未存在过的私钥好。

4

2 回答 2

5

这是在 Windows 上执行此操作的一种方法

  1. 使用适用于 .Net 的 Azure Key Vault SDK,在 Azure Key Vault 的 HSM 中创建密钥对

    // Assuming you have a keyVaultClient object using the SDK
    var keyBundle = keyVaultClient.CreateKeyAsync(keyVaultUri, "myKey01", "RSA-HSM", 2048).GetAwaiter().GetResult();
    
  2. 将创建的密钥对的公钥作为 CSP blob 获取

    var rsaCryptoProvider = new RSACryptoServiceProvider();
    var rsaParameters = new RSAParameters()
    {
        Modulus = keyBundle.Key.N,
        Exponent = keyBundle.Key.E
    };
    rsaCryptoProvider.ImportParameters(rsaParameters);
    var cspBlob = rsaCryptoProvider.ExportCspBlob(false);
    
  3. PKCS10 (CSR) 的 subjectPublicKeyInfo 组件包含有关被认证的公钥的信息。subjectPublicKeyInfo 是 Windows Cryptography API: Next Generation (CNG) 的 ASN1 编码CERT_PUBLIC_KEY_INFO 结构

    本部分需要熟悉如何使用 Windows 加密 API:下一代 (CNG)。CNG 是一个原生 API,您需要使用 PInvoke (DllImport) 从托管代码中调用它。

    一个。使用 NCryptOpenStorageProvider(SO 上的链接限制,搜索 MSDN)

    [DllImport("ncrypt.dll", CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
    private static extern ErrorCode NCryptOpenStorageProvider(
        [Out] out SafeNCryptProviderHandle phProvider,
        string pszProviderName,
        uint dwFlags);
    

    打开 CNG 密钥存储提供程序 -

    SafeNCryptProviderHandle providerHandle = null;
    var result = NCryptOpenStorageProvider(
        out providerHandle,
        null,
        0);
    

    湾。使用 NCryptImportKey(SO 上的链接限制,搜索 MSDN)

    [DllImport("ncrypt.dll", CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
    private static extern int NCryptImportKey(
        SafeNCryptProviderHandle hProvider,
        IntPtr hImportKey,     // NCRYPT_KEY_HANDLE
        string pszBlobType,
        IntPtr pParameterList, // NCryptBufferDesc *
        [Out] out SafeNCryptKeyHandle phKey,
        [MarshalAs(UnmanagedType.LPArray)] byte[] pbData,
        int cbData,
        uint dwFlags);
    

    将 (2) 中的 cspBlob 导入密钥服务提供者

    SafeNCryptKeyHandle keyHandle;
    var result = NCryptImportKey(
        providerHandle,
        IntPtr.Zero,
        "CAPIPUBLICBLOB",
        IntPtr.Zero,
        out keyHandle,
        cspBlob,
        cspBlob.Length,
        0x00000040);
    

    C。keyHandle 现在可以与 CryptExportPublicKeyInfo 一起使用 -(SO 上的链接限制,搜索 MSDN)为 CSR 对象创建 CERT_PUBLIC_KEY_INFO 结构。查看文档中提供的示例。

  4. 填写PKCS10(CSR)的其他字段,ASN1对其进行编码。

  5. 使用适当的散列算法创建 (5) 的编码结果的散列。使用 (1) 中创建的密钥对的私钥对哈希进行签名

    var signature = keyVaultClient.SignAsync(keyBundle.KeyIdentifier.Identifier, "RS256", hash).GetAwaiter().GetResult();

  6. 将签名附加到 (5) 的编码结果中,然后 ANS1 再次对其进行编码。

于 2016-01-25T18:07:45.367 回答
3

您可能会发现使用 Windows CertEnroll COM 接口更容易:创建初始化 IX509CertificateRequestPkcs10 对象( https://msdn.microsoft.com/en-us/library/windows/desktop/aa377505(v=vs.85).aspx ),填充其属性,然后获取其 RawDataToBeSigned 属性并将其发送到 Azure Key Vault 以进行签名。这可以从本机代码、.NET 等调用。

另一种 [但更复杂的] 方法是使用构建 COM 接口的底层 Windows API。此示例 ( https://msdn.microsoft.com/en-us/library/windows/desktop/aa382364(v=vs.85).aspx ) 演示了如何生成和签署这样的 PKCS#10。在我的脑海中,您应该能够通过替换对 CryptSignAndEncodeCertificate 的调用来调整示例:

  1. 调用 CryptEncodeObjectEx 到 ASN.1 将 CERT_REQUEST_INFO 对象编码为二进制;和

  2. 调用 Key Vault 以签署该二进制 blob。

  3. 然后,您需要构造一个 CERT_SIGNED_CONTENT_INFO,设置:

    一个。ToBeSigned 成员到 #1 的编码二进制文件;

    湾。用于使用 Key Vault 签名的算法的 SignatureAlgorithm 成员;和

    C。从 Key Vault 返回的签名的签名成员。

  4. 然后,您将再次调用 CryptEncodeObjectEx 以 ASN.1 将生成的 PKCS #10 编码为二进制。

上面的解决方案是有效的,但实际上将通过 .NET 互操作通过 IMO 更复杂的方法(将示例中的 Crypto API v1.0 调用替换为 Crypto Next Gen 调用)。除非我有特定的原因,否则我不会从那里开始。

于 2016-01-26T17:34:29.423 回答