如何将 CSR 文本文件转换为 .NET Core/Standard CertificateRequest 以进行签名?

Posted

技术标签:

【中文标题】如何将 CSR 文本文件转换为 .NET Core/Standard CertificateRequest 以进行签名?【英文标题】:How to convert a CSR text file into .NET Core/ Standard CertificateRequest for Signing? 【发布时间】:2021-05-02 18:04:05 【问题描述】:

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

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

我可以很容易地完成 CSR:

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

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

    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 机制或构造函数允许这样做。

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

【问题讨论】:

【参考方案1】:

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

签署证书请求是一项重大决定。请求是否仅使用授权使用的名称?它是否将自己推销给另一个颁发证书的机构?是否有任何扩展请求您不理解其含义?它是否自称是时间戳权威、代码签名证书或任何其他有限用途?

通过签署外部请求,您是在尝试成为“真正的”CA。你在做撤销吗?您正在记录发行吗?

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

如果您使用受控访问,则更有限的版本是以您自己的自定义格式(另请参阅@ 987654322@)。然后你知道你没有被要求做你不想做的事情。不幸的是,PublicKey.CreateFromSubjectPublicKeyInfo 是 .NET 6 中的新功能。幸运的是,它很简单:

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/Standard CertificateRequest 以进行签名?的主要内容,如果未能解决你的问题,请参考以下文章

如何将带有参数数组的字符串 xml 转换为 .NET Core 中的对象

ASP.NET Core —上传.json文件并转换为List

将 WCF 应用程序从 .Net 框架转换为 .Net Core 时如何移植 <system.serviceModel> 配置?

如何将私钥转换为 RSA 私钥?

如何在 ASP Net Core Web API 上正确地将列表转换为 IQueryable

将Visual Studio项目转换为Dot Net Core项目 csproj to xproj