如何将 CSR 文本文件转换为 .NET Core/标准证书请求以进行签名? [英] How to convert a CSR text file into .NET Core/ Standard CertificateRequest for Signing?

查看:32
本文介绍了如何将 CSR 文本文件转换为 .NET Core/标准证书请求以进行签名?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很多类似的问题,但我没有看到好的答案.

Lots of similar questions, but I don't see a good answer.

我有一个基于云的应用程序,在现场的客户站点上安装了一个代理.我想让代理在安装时生成 CSR 并通过 HTTPS 将请求上传到云服务,在那里我将使用云服务证书(代理将信任)对其进行签名并返回签名证书.此证书将用于代理身份验证、加密和文件签名.

I have a cloud-based application with an agent installed on customer sites in the field. I want to have the agent, upon installation, generate a CSR and upload the request over HTTPS to the cloud service, where I will sign it with the cloud service certificate (that the agent will trust) and return the signed certificate. This certificate will be used for agent authentication, encryption, and file signatures.

我可以很容易地制作 CSR:

I'm able to make the CSR pretty easily:

    public string GenerateAgentCsr(Guid customerId)
    {
        var domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName;
        var domainDistinguishedName = string.Join(",DC=", domain.Split("."));
        var distinguishedName = $"DC={Environment.MachineName},DC={domainDistinguishedName},O={customerId}";
        var rsa = RSA.Create(1024);
        var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256,
            RSASignaturePadding.Pkcs1);
        request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
        request.CertificateExtensions.Add(new X509KeyUsageExtension(
            X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.DataEncipherment |
            X509KeyUsageFlags.NonRepudiation, false));

        var armored = request.AsCsr();
        return armored;
    }

    public static string AsCsr(this CertificateRequest request)
    {
        var encoded = request.CreateSigningRequest();
        var payload = Convert.ToBase64String(encoded);
        using var stream = new MemoryStream();
        using (var writer = new StreamWriter(stream, Encoding.UTF8, 512, true))
        {
            writer.WriteLine("-----BEGIN CERTIFICATE REQUEST-----");
            writer.WriteLine(payload.Slice());
            writer.WriteLine("-----END CERTIFICATE REQUEST-----");
            writer.Flush();
        }

        stream.Position = 0;
        using (var reader = new StreamReader(stream))
        {
            return reader.ReadToEnd();
        }
    }

...所以我可以将其发送到云服务器,但随后我立即遇到了问题.我的计划是采用这样的方法:

...so I can send this up to the cloud server, but then I immediately run into a problem. My plan was to have a method like so:

    public X509Certificate2 SignCertificate(CertificateRequest csr)
    {
        var signedCert = csr.Create(GetCertificateAuthorityCertificate(), DateTimeOffset.Now, DateTimeOffset.Now.AddYears(10),
            new byte[] { 1, 2, 3, 4 });
        return signedCert;
    }

...但我实际上无法将 CSR 转换为 CertificateRequest.没有允许这样做的 Parse 机制或构造函数.

...but I can't actually convert the CSR into a CertificateRequest. There's no Parse mechanism or constructor that will allow this.

那么...一旦我有了 CSR,我该如何正确解析并使用我的云服务证书对其进行签名,以便我可以将其发送回代理?

So... once I have the CSR, how do I properly parse and sign it with my cloud service certificate so that I can send it back to the agent?

推荐答案

类型可以帮助您填充 CertificateRequest 对象的唯一方法是使用 System.Formats.Asn1.AsnReader 读取数据.

The only way that types will help you with populating a CertificateRequest object is by reading the data with System.Formats.Asn1.AsnReader.

签署证书请求是一项重大决定.请求是否只使用它被授权使用的名称?它是否将自己提升到另一个颁发证书的机构?是否有任何您不理解其含义的扩展请求?它声称自己是时间戳机构、代码签名证书或任何其他有限用途吗?

Signing a certificate request is a major decision. Does the request use only names that it is authorized to use? Is it promoting itself to another issuing certificate authority? Are there any extensions requested that you don't understand the meaning of? Is it claiming to be a TimeStamp Authority, or a Code Signing Certificate, or any other limited-purpose?

通过签署外部请求,您正在努力成为一个真实"的人.CA.你在做撤销吗?你在记录发行吗?

By signing an external request you're trying to be a "real" CA. Are you doing revocation? Are you logging the issuance?

.NET 有 SubjectAlternativeNameBuilder 来帮助构建 SAN 扩展,但没有一个很好的方法来读取它们......因为 SubjectAlternativeNames 比它们通常使用的要复杂得多.所以没有很好的方法来回答姓名问题.

.NET has the SubjectAlternativeNameBuilder to help build SAN extensions, but doesn't have a good way to read them back... because SubjectAlternativeNames are much more complex than they generally are used as. So there's no good way to answer the names question.

如果您使用受控访问,则此方法的一个更有限的版本是以您自己的自定义格式(另请参阅<代码>rsa.ExportSubjectPublicKeyInfo()).然后你知道你不会被要求做你不想做的事情.不幸的是,PublicKey.CreateFromSubjectPublicKeyInfo 是 .NET 6 中的新增功能.幸运的是,这很容易:

A much more limited version of this, if you're using controlled access, would be to transmit just the SubjectPublicKeyInfo value of the public key (and whatever other information you want to include) in your own custom format (see also rsa.ExportSubjectPublicKeyInfo()). Then you know you're not being asked to do something that you don't want to do. Unfortunately, PublicKey.CreateFromSubjectPublicKeyInfo is new in .NET 6. Fortunately, it's easy:

private static PublicKey CreateFromSubjectPublicKeyInfo(ReadOnlyMemory<byte> data)
{
    AsnReader reader = new AsnReader(data, AsnEncodingRules.DER);
    AsnReader spki = reader.ReadSequence();
    reader.ThrowIfNotEmpty();

    AsnReader algorithmIdentifier = spki.ReadSequence();
    string algOid = algorithmIdentifier.ReadObjectIdentifier();
    ReadOnlyMemory<byte> algParameters = default;

    if (algOid.HasData)
    {
        algParameters = algorithmIdentifier.ReadEncodedValue();
    }

    algorithmIdentifier.ThrowIfNotEmpty();

    byte[] publicKey = spki.ReadBitString(out _);
    spki.ThrowIfNotEmpty();

    return new PublicKey(
        new Oid(algOid, null),
        algParameters.ToArray(),
        publicKey);
}

这篇关于如何将 CSR 文本文件转换为 .NET Core/标准证书请求以进行签名?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆