在不同计算机上生成和签名证书C#

问题描述 投票:0回答:2

我需要生成用于代理之间安全通信的证书。每个代理生成一个证书,并且必须将其发送到另一台计算机上的系统CA,以进行签名(并由其他代理信任)。我正在使用C#,并为代理使用以下代码:

 //generate certificate
        ECDsa elipticCurveNistP256Key = ECDsa.Create(ECCurve.CreateFromValue("1.2.840.10045.3.1.7")); // nistP256 curve
        CertificateRequest certificateRequest = new CertificateRequest("CN=" + agentId, elipticCurveNistP256Key, HashAlgorithmName.SHA256);
        certificateRequest.CertificateExtensions.Add(
            new X509BasicConstraintsExtension(false, false, 0, false));
        certificateRequest.CertificateExtensions.Add(
            new X509KeyUsageExtension(
                X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation,
                false));

        // Add the SubjectAlternativeName extension
        var sanBuilder = new SubjectAlternativeNameBuilder();
        sanBuilder.AddIpAddress(IPAddress.Parse(agentIpAddress));
        certificateRequest.CertificateExtensions.Add(sanBuilder.Build());

        certificateRequest.CertificateExtensions.Add(
            new X509EnhancedKeyUsageExtension(
                new OidCollection
                {
                    new Oid("1.3.6.1.5.5.7.3.8")
                },
                true));

        certificateRequest.CertificateExtensions.Add(
            new X509SubjectKeyIdentifierExtension(certificateRequest.PublicKey, false));

以及CA系统的以下代码:

  X509Certificate2 signedCertificate = certificateRequest.Create(
            caCertificatePFX,
            DateTimeOffset.UtcNow.AddDays(-1),
            DateTimeOffset.UtcNow.AddDays(30),
            new byte[] {1, 2, 3, 4});

当然,我也使用代码在此处未显示的机器之间进行通信。但是我至少有两个问题:

  1. 我希望在证书生成和签名之间有一个完全的隔离,但是即使尝试了很多,这也是我可以设法上班的唯一代码。如果我没有记错的话,此代码在CA系统上创建了证书,这不是理想的情况(CA可以访问代理私钥),但是如果我没有找到更好的证书,那么我可以接受。

  2. 第二个问题是,即使我接受第一个问题,我仍然需要将CertificateRequest对象从一台计算机发送到另一台计算机,并且CertificateRequest无法序列化。我发现方法CreateSigningRequest()“创建代表当前对象状态的ASN.1 DER编码的PKCS#10 CertificationRequest值”。但是我还没有找到使它再次成为CertificateRequest对象的方法,以便可以运行CA系统代码。

有人知道我该怎么做吗?希望将证书的生成和证书的签名完全分开,但是如果那不可能的话,至少要创建一个CertificateRequest对象。

谢谢

c# security x509certificate2
2个回答
0
投票

如您所述,没有办法回读PKCS#10请求。这主要是因为缺少太多东西,无法成为“确定的”证书颁发机构,因此拥有读者只会使很多“不良的”证书颁发机构受益。 (由于您的CA不支持吊销,因此它也是一个“不良”的CA,但是您可以使用较短的生存期证书来缓解这种情况。)

PKCS#10请求包含:

  • 数据格式版本
  • 一个名称(可能是请求者想要的名称)
  • 公钥
  • 属性
    • 所需的扩展名位于此处(EKU,主题备用名称等)
  • 签名,以证明请求者具有私钥。

如果您不使用数据格式,则数据格式版本是无关紧要的,并且对于“封闭式”颁发者(仅向直接已知方颁发证书的CA),签名并不是很重要。因此,您只需要传输公钥以及请求所需的任何其他数据(查看您的当前代码,代理ID和IP地址)。

唯一棘手的部分是发送公钥...但是使用.NET Core 3.0+,您可以将所有密钥标准化为其SubjectPublicKeyInfo格式:

byte[] spki = elipticCurveNistP256Key.ExportSubjectPublicKeyInfo();

虽然PublicKey类型具有ImportSubjectPublicKeyInfo方法非常聪明,但尚未发生。对于通用解析,您想尝试所有主要的密钥类型,但是由于您是另一侧的封闭式CA,因此您可以先验地知道它是ECDSA:

using (ECDsa clientPub = ECDsa.Create())
{
    clientPub.ImportSubjectPublicKeyInfo(transmittedSpki, out _);

    // the rest of your code goes here.
}

0
投票

我强烈建议使用CA软件签署证书请求。期间。

任何尝试拥有自己的CA代码的尝试都会使解决方案在许多方面都不可靠,易碎且容易出错。从Microsoft ADCS(Windows)和EJBCA(Windows / Linux)开始,有几个选项。任何其他设计都将很糟糕。

© www.soinside.com 2019 - 2024. All rights reserved.