【问题标题】:Sign a CSR with Azure Key Vault使用 Azure Key Vault 签署 CSR
【发布时间】:2020-06-21 06:25:51
【问题描述】:

如何使用 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 的服务来说,这似乎是如此基本......

谢谢

【问题讨论】:

  • 嗨,你解决了吗?
  • 不,SO 中似乎没有人知道答案。
  • 您是否取得了成功,或者您可以分享您为手动执行这些步骤而编写的任何代码(即使使用 RSA)?

标签: c# azure azure-keyvault


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    KV 有签名操作,但它并不特定于任何数据类型(例如证书请求)。

    KV .NET SDK 提供了这个 https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.keyvault.keyvaultclient.signwithhttpmessagesasync?view=azure-dotnet-legacy,它只是 REST API https://docs.microsoft.com/en-us/rest/api/keyvault/ 的一个包装器

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

    【讨论】:

    • 谢谢!不幸的是,这是一个非常简单的 KV 代码,我正在寻找一个 x509 签名特定代码,它将负责在 ECDSA 中进行签名、构建签名证书等。还是谢谢!
    • 我确实尝试过,但这与我的要求相去甚远!还是谢谢。
    猜你喜欢
    • 2021-11-06
    • 2016-04-24
    • 1970-01-01
    • 2020-05-16
    • 2020-05-04
    • 1970-01-01
    • 2019-12-01
    • 2019-06-09
    • 1970-01-01
    相关资源
    最近更新 更多