我需要生成用于代理之间安全通信的证书。每个代理生成一个证书,并且必须将其发送到另一台计算机中的系统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是不可序列化的。我找到了CreateSigningRequest((方法,该方法"创建一个ASN.1 DER编码的PKCS#10 CertificateRequest值,表示当前对象的状态。"但是,我还没有找到一种方法,使其再次成为CertificateRequest对象,以便运行CA系统代码。
有人知道我该怎么做吗?希望能够完全分离证书生成和证书签名,但如果这不可能,至少可以创建CertificateRequest对象。
我在跑步。Net Framework 4.7.2,我需要维护它才能使用以前开发的Windows窗体。
感谢
正如您所指出的,没有办法读回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.
}
我强烈建议使用CA软件对证书请求进行签名。时期
任何推出CA代码的尝试都会使解决方案在许多方面变得不可靠、脆弱和容易出错。有几个选项,从Microsoft ADCS(Windows(和EJBCA(Windows/Linux(开始。任何其他的设计都会很糟糕。