31 lines
1.7 KiB
C#
31 lines
1.7 KiB
C#
using System.Security.Cryptography;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
|
|
namespace Fleet.Identity;
|
|
|
|
/// <summary>
|
|
/// 点对点会话的 TLS 证书:自签名的 ECDSA P-256(和身份密钥是两把不同的密钥)。
|
|
/// 对端不按证书链校验,而是按 SPKI 的 SHA-256 指纹校验(指纹由服务端经 Agent 列表下发)。
|
|
/// </summary>
|
|
public static class NodeCertificate
|
|
{
|
|
/// <summary>生成自签名证书,返回无口令的 PFX 字节(文件权限由写入方设为 0600)。</summary>
|
|
public static byte[] CreateSelfSignedPfx(string commonName, TimeSpan validity, TimeProvider time)
|
|
{
|
|
using ECDsa key = ECDsa.Create(ECCurve.NamedCurves.nistP256);
|
|
var request = new CertificateRequest("CN=" + commonName, key, HashAlgorithmName.SHA256);
|
|
request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, critical: true));
|
|
request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(
|
|
[new Oid("1.3.6.1.5.5.7.3.1"), new Oid("1.3.6.1.5.5.7.3.2")], critical: false));
|
|
DateTimeOffset now = time.GetUtcNow();
|
|
using X509Certificate2 certificate = request.CreateSelfSigned(now.AddDays(-1), now.Add(validity));
|
|
return certificate.Export(X509ContentType.Pfx);
|
|
}
|
|
|
|
public static X509Certificate2 LoadPfx(byte[] pfx) => X509CertificateLoader.LoadPkcs12(pfx, null, X509KeyStorageFlags.Exportable);
|
|
|
|
/// <summary>证书公钥(SPKI)的 SHA-256:对端用它来固定这张证书。</summary>
|
|
public static byte[] SpkiFingerprint(X509Certificate2 certificate) =>
|
|
SHA256.HashData(certificate.PublicKey.ExportSubjectPublicKeyInfo());
|
|
}
|