在不同的机器上生成和签署证书 C#
Generate and sign certificate in different machines C#
我需要生成证书以用于代理之间的安全通信。每个代理生成一个证书,并且必须将其发送到另一台机器上的系统 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});
当然,我也使用代码进行机器之间的通信,我没有在这里显示。但我至少有两个问题:
我希望将证书生成和签名完全分开,但即使尝试了很多次,这也是我能够开始工作的唯一代码。如果我没记错的话,这段代码在 CA 系统上创建了证书,这不是理想的场景(CA 可以访问代理私钥),但如果我没有找到更好的,我可以接受。
第二个问题是,即使我接受了第一个问题,我仍然需要将 CertificateRequest 对象从一台机器发送到另一台机器,而 CertificateRequest 是不可序列化的。我找到了 "Creates an ASN.1 DER-encoded PKCS#10 CertificationRequest value representing the state of the current object." 的方法 CreateSigningRequest() 但是我还没有找到一种方法来使它再次成为 CertificateRequest 对象,这样我就可以 运行 CA 系统代码。
有人知道我该怎么做吗?希望将证书生成和证书签名完全分开,但如果不可能,至少要重新创建 CertificateRequest 对象。
我正在 运行ning .Net Framework 4.7.2,我需要维护它才能使用以前开发的 Windows 表单。
谢谢
如您所述,无法回读 PKCS#10 请求。这主要是因为 "OK" 证书颁发机构缺少太多东西,因此拥有 reader 只会产生很多 "bad" 证书颁发机构。 (由于您的 CA 不支持吊销,它也是一个 "bad" CA,但您正在使用短期证书来缓解这种情况。)
PKCS#10 请求包含:
- 一个数据格式版本
- 一个名字(大概是请求者想要的名字)
- 一个public键
- 属性
- 请求的扩展在这里(EKU、主题备用名称等)
- 签名,证明请求者有私钥。
如果您不使用数据格式,则数据格式版本无关紧要,并且签名对于 "closed" 颁发者(仅向直接已知方颁发证书的 CA)来说并不重要。因此,您只需要传输 public 密钥和请求所需的任何其他数据(查看您当前的代码、代理 ID 和 IP 地址)。
唯一棘手的部分是发送 public 密钥...但是使用 .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.
}
我强烈建议使用 CA 软件来签署证书请求。期间.
任何尝试拥有您的 CA 代码的尝试都会使解决方案在许多方面变得不可靠、脆弱且容易出错。有几个选项,首先是 Microsoft ADCS (Windows) 和 EJBCA (Windows/Linux)。任何其他设计都会很糟糕。
我需要生成证书以用于代理之间的安全通信。每个代理生成一个证书,并且必须将其发送到另一台机器上的系统 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});
当然,我也使用代码进行机器之间的通信,我没有在这里显示。但我至少有两个问题:
我希望将证书生成和签名完全分开,但即使尝试了很多次,这也是我能够开始工作的唯一代码。如果我没记错的话,这段代码在 CA 系统上创建了证书,这不是理想的场景(CA 可以访问代理私钥),但如果我没有找到更好的,我可以接受。
第二个问题是,即使我接受了第一个问题,我仍然需要将 CertificateRequest 对象从一台机器发送到另一台机器,而 CertificateRequest 是不可序列化的。我找到了 "Creates an ASN.1 DER-encoded PKCS#10 CertificationRequest value representing the state of the current object." 的方法 CreateSigningRequest() 但是我还没有找到一种方法来使它再次成为 CertificateRequest 对象,这样我就可以 运行 CA 系统代码。
有人知道我该怎么做吗?希望将证书生成和证书签名完全分开,但如果不可能,至少要重新创建 CertificateRequest 对象。
我正在 运行ning .Net Framework 4.7.2,我需要维护它才能使用以前开发的 Windows 表单。
谢谢
如您所述,无法回读 PKCS#10 请求。这主要是因为 "OK" 证书颁发机构缺少太多东西,因此拥有 reader 只会产生很多 "bad" 证书颁发机构。 (由于您的 CA 不支持吊销,它也是一个 "bad" CA,但您正在使用短期证书来缓解这种情况。)
PKCS#10 请求包含:
- 一个数据格式版本
- 一个名字(大概是请求者想要的名字)
- 一个public键
- 属性
- 请求的扩展在这里(EKU、主题备用名称等)
- 签名,证明请求者有私钥。
如果您不使用数据格式,则数据格式版本无关紧要,并且签名对于 "closed" 颁发者(仅向直接已知方颁发证书的 CA)来说并不重要。因此,您只需要传输 public 密钥和请求所需的任何其他数据(查看您当前的代码、代理 ID 和 IP 地址)。
唯一棘手的部分是发送 public 密钥...但是使用 .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.
}
我强烈建议使用 CA 软件来签署证书请求。期间.
任何尝试拥有您的 CA 代码的尝试都会使解决方案在许多方面变得不可靠、脆弱且容易出错。有几个选项,首先是 Microsoft ADCS (Windows) 和 EJBCA (Windows/Linux)。任何其他设计都会很糟糕。