使用 Azure Key Vault 签署 CSR

Sign a CSR with Azure Key Vault

如何使用 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 的服务来说似乎非常基础...

谢谢

KV 有一个符号操作,但它不特定于任何数据类型(例如证书请求)。

KV .NET SDK 提供此 https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.keyvault.keyvaultclient.signwithhttpmessagesasync?view=azure-dotnet-legacy which is just a wrapper over REST APIs https://docs.microsoft.com/en-us/rest/api/keyvault/

这不是您想要的,但我写了一些代码来演示 C# KV encrypt/decrypt 这应该可以帮助您入门 https://github.com/x509cert/AzureKeyVault

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);

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