我想在Azure Key Vault中的HSM中生成私钥,然后创建包含相应公钥的证书签名请求CSR。
现在生成公钥,以及随后的CSR,甚至可能在Key Vault中生成 - 我没有看到在文档中生成相应公钥的任何提及? (或者我可能只是不了解HSM的性质?)
似乎是在其他地方创建密钥和CSR并将私钥导入Key Vault HSM。这显然不如HSM之外从未存在的私钥那么好。
答案 0 :(得分:4)
以下是在Windows上执行此操作的方法
使用Azure Key Vault SDK for .Net,在Azure Key Vault中的HSM中创建密钥对
// Assuming you have a keyVaultClient object using the SDK var keyBundle = keyVaultClient.CreateKeyAsync(keyVaultUri, "myKey01", "RSA-HSM", 2048).GetAwaiter().GetResult();
获取已创建密钥对的公钥作为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);
PKCS10(CSR)的subjectPublicKeyInfo组件包含有关正在认证的公钥的信息。 subjectPublicKeyInfo是Windows密码学API:下一代(CNG)的ASN1编码CERT_PUBLIC_KEY_INFO structure。
本节需要熟悉如何使用Windows Cryptography API:Next Generation(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);
℃。 keyHandle现在可以与CryptExportPublicKeyInfo一起使用 - (SO上的链接限制,搜索MSDN)为CSR对象创建CERT_PUBLIC_KEY_INFO结构。请查看文档中提供的示例。
填写PKCS10(CSR)的其他字段,ASN1对其进行编码。
使用appopriate散列算法创建(5)的编码结果的散列。使用在(1)
中创建的密钥对的私钥对哈希进行签名var signature = keyVaultClient.SignAsync(keyBundle.KeyIdentifier.Identifier," RS256",hash).GetAwaiter()。GetResult();
将签名附加到(5)的编码结果,ANS1再次对其进行编码。
答案 1 :(得分:2)
您可能会发现使用Windows CertEnroll COM接口更容易:创建和初始化IX509CertificateRequestPkcs10对象(https://msdn.microsoft.com/en-us/library/windows/desktop/aa377505(v=vs.85).aspx),填充其属性,然后获取其RawDataToBeSigned属性并将其发送到要签名的Azure密钥保管库。这可以从本机代码,.NET等中调用。
另一种[但更复杂]的方法是使用构建COM接口的底层Windows API。此示例(https://msdn.microsoft.com/en-us/library/windows/desktop/aa382364(v=vs.85).aspx)遍历生成和签署此类PKCS#10。在我的脑海中,您应该能够通过将CryptSignAndEncodeCertificate的调用替换为:
来调整样本。对CryptEncodeObjectEx的调用,ASN.1将CERT_REQUEST_INFO对象编码为二进制;以及
致电Key Vault以签署该二进制blob。
然后您需要构建一个CERT_SIGNED_CONTENT_INFO,设置:
一个。来自#1;
的编码二进制文件的ToBeSigned成员湾用于与Key Vault签名的算法的SignatureAlgorithm成员;和
℃。密钥保险库返回签名的签名成员。
然后再次调用CryptEncodeObjectEx,ASN.1将生成的PKCS#10编码为二进制文件。
上面的解决方案是有效的,但实际上将通过.NET interop(通过Crypto Next Gen调用替换示例中的Crypto API v1.0调用)来实现IMO是更复杂的方法。除非我有特殊原因,否则我不会从那里开始。