c# - 使用 Azure Key Vault 签署 CSR

标签 c# azure azure-keyvault

如何使用 Azure Key Vault 实现非常基本的 CSR 签名 HSM 功能?

我发现了一个非常漫长的手动过程来以某种方式实现它:

  1. 在 Key Vault 中创建私钥
  2. 创建 CSR,使用 SHA256 对其进行消化
  3. 使用 Sign() 方法用之前的私钥对摘要进行签名
  4. 创建本地 x.509 证书并附加签名
  5. 将新签名的证书上传到 Key Vault

问题是,它是手动的,时间长(而且有相当多的延迟)并且容易出错。另外,我还没有找到相关的 C# 代码示例,我正在寻找 EC 而不是 RSA。

问题是,Key Vault中有一个简单的CertificateRequest.Sign()函数吗?对于类似 HSM 的服务来说,这似乎是非常基本的...

谢谢

最佳答案

This blog post by Vitaliy Slepakov描述了他创建的一个解决方案,该解决方案使用 C#/.NET Core 实现上面列出的步骤。

代码可以在这里找到: https://github.com/vslepakov/keyvault-ca/

其核心如下:

byte[] certificateRequest = /* ... */;
string issuerCertificateName = /* ... */;
KeyVaultServiceClient keyVaultServiceClient = /* ... */;
X509SignatureGenerator generator = /* see next section */;

var pkcs10CertificationRequest = new Pkcs10CertificationRequest(certificateRequest);
//TODO: Validate CSR via pkcs10CertificationRequest.Verify()

var info = pkcs10CertificationRequest.GetCertificationRequestInfo();
var notBefore = DateTime.UtcNow.AddDays(-1);

// Get the RSA public key from the CSR
var asymmetricKeyParameter = Org.BouncyCastle.Security.PublicKeyFactory.CreateKey(info.SubjectPublicKeyInfo);
var rsaKeyParameters = (Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)asymmetricKeyParameter;
var rsaKeyInfo = new RSAParameters
{
    Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned(),
    Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned()
};
var publicKey = RSA.Create(rsaKeyInfo);
//TODO: Validate publicKey

var certBundle = await keyVaultServiceClient.GetCertificateAsync(issuerCertificateName).ConfigureAwait(false);

var signingCert = new X509Certificate2(certBundle.Cer);

// new serial number
var serialNumber = new byte[SerialNumberLength];
RandomNumberGenerator.Fill(serialNumber);
serialNumber[0] &= 0x7F;

var subjectDN = new X500DistinguishedName(subjectName);
var request = new CertificateRequest(subjectDN, publicKey, GetRSAHashAlgorithmName(hashSizeInBits), RSASignaturePadding.Pkcs1);

// Basic constraints
request.CertificateExtensions.Add(
    new X509BasicConstraintsExtension(caCert, caCert, 0, true));

// Subject Key Identifier
var ski = new X509SubjectKeyIdentifierExtension(
    request.PublicKey,
    X509SubjectKeyIdentifierHashAlgorithm.Sha1,
    false);

request.CertificateExtensions.Add(ski);

// Authority Key Identifier
if (issuerCAKeyCert != null)
    request.CertificateExtensions.Add(BuildAuthorityKeyIdentifier(issuerCAKeyCert));
else
    request.CertificateExtensions.Add(BuildAuthorityKeyIdentifier(subjectDN, serialNumber.Reverse().ToArray(), ski));

if (caCert)
    request.CertificateExtensions.Add(
        new X509KeyUsageExtension(
            X509KeyUsageFlags.DigitalSignature |
            X509KeyUsageFlags.KeyCertSign |
            X509KeyUsageFlags.CrlSign,
            true));
else
{
    // Key Usage
    var defaultFlags =
        X509KeyUsageFlags.DigitalSignature |
        X509KeyUsageFlags.DataEncipherment |
        X509KeyUsageFlags.NonRepudiation |
        X509KeyUsageFlags.KeyEncipherment;

    request.CertificateExtensions.Add(new X509KeyUsageExtension(defaultFlags, true));

    // Enhanced key usage
    request.CertificateExtensions.Add(
        new X509EnhancedKeyUsageExtension(
            new OidCollection {
            new Oid("1.3.6.1.5.5.7.3.1"),
            new Oid("1.3.6.1.5.5.7.3.2") }, true));
}

if (issuerCAKeyCert != null)
{
    if (notAfter > issuerCAKeyCert.NotAfter)
    {
        notAfter = issuerCAKeyCert.NotAfter;
    }
    if (notBefore < issuerCAKeyCert.NotBefore)
    {
        notBefore = issuerCAKeyCert.NotBefore;
    }
}

var issuerSubjectName = issuerCAKeyCert != null ? issuerCAKeyCert.SubjectName : subjectDN;
X509Certificate2 signedCert = request.Create(
    issuerSubjectName,
    generator,
    notBefore,
    notAfter,
    serialNumber);

custom X509SignatureGenerator implementation is here并使用以下 Key Vault SDK 方法:

HashAlgorithm hash = /* see GitHub */;
var digest = hash.ComputeHash(data);

var resultKeyVaultPkcs = await keyVaultClient.SignAsync(signingKey, algorithm, digest, RSASignaturePadding.Pkcs1);

希望您可以调整此代码以满足您的需求。我也会这样做。 😀

关于c# - 使用 Azure Key Vault 签署 CSR,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62495165/

相关文章:

azure - 增加在 Azure 上运行的 Dockerized ASP.NET Core 站点的最大上传大小限制?

asp.net - VSTS CI 在部署时使 Azure 应用服务脱机

azure - 在 Azure Key Vault 支持的 Databricks 中创建 secret 范围失败

azure - NET Core应用程序无法访问Azure Key Vault

javascript - MVC Controller 方法不是从 ajax 调用的

c# - 编译器如何为实数文字选择隐式运算符重载

c# - Windows Phone 8 MonoGame 初始化未被调用

c# - SSH.NET 库 - SshClient.Dispose(),公共(public)连接

javascript - 通过 Azure 存储以 HTML 格式获取 JSON 文件

azure - 以编程方式创建 Azure KeyVault secret 时,如何修复“"Operation ' set' not allowed”错误?