138 lines
5.4 KiB
C#
138 lines
5.4 KiB
C#
using System.Security.Cryptography;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using ln.type;
|
|
|
|
namespace ln.ai.assistant;
|
|
|
|
public class CertificateAuthority
|
|
{
|
|
public string StoragePath { get; }
|
|
public string Name { get; }
|
|
|
|
private X509Certificate2 _privateCertificate;
|
|
|
|
public CertificateAuthority(string storagePath, string caName)
|
|
{
|
|
StoragePath = storagePath;
|
|
Name = caName;
|
|
|
|
if (!Directory.Exists(StoragePath))
|
|
Directory.CreateDirectory(StoragePath);
|
|
|
|
Initialize();
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
string caCertFileName = Path.Combine(StoragePath, ".ca.pem");
|
|
string caKeyFileName = Path.Combine(StoragePath, ".ca.key");
|
|
|
|
if (File.Exists(caCertFileName) && File.Exists(caKeyFileName))
|
|
{
|
|
_privateCertificate = X509Certificate2.CreateFromPemFile(caCertFileName, caKeyFileName);
|
|
}
|
|
else
|
|
{
|
|
using (RSA rsa = RSA.Create(4096))
|
|
{
|
|
var request = new CertificateRequest($"CN={Name}", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
|
request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.CrlSign | X509KeyUsageFlags.KeyCertSign, false));
|
|
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, false));
|
|
_privateCertificate = request.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now + TimeSpan.FromDays(3650));
|
|
|
|
WritePemFile(caCertFileName, _privateCertificate);
|
|
WritePemFile(caKeyFileName, rsa);
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool GetOrCreateCertificate(string distinguishedName, out X509Certificate2? certificate)
|
|
{
|
|
return TryLoadCertificate(distinguishedName, out certificate) ||
|
|
CreateSignedCertificate(distinguishedName, out certificate);
|
|
}
|
|
|
|
private bool CreateSignedCertificate(string distinguishedName, out X509Certificate2? certificate)
|
|
{
|
|
string certFileName = Path.Combine(StoragePath, $"{distinguishedName}.cert.pem");
|
|
string keyFileName = Path.Combine(StoragePath, $"{distinguishedName}.key.pem");
|
|
|
|
using (RSA rsa = RSA.Create(4096))
|
|
{
|
|
var request = new CertificateRequest($"CN={distinguishedName}", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
|
request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment |
|
|
X509KeyUsageFlags.DigitalSignature, false));
|
|
request.CertificateExtensions.Add(
|
|
new X509EnhancedKeyUsageExtension(new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, false));
|
|
|
|
var san = new SubjectAlternativeNameBuilder();
|
|
san.AddDnsName(distinguishedName);
|
|
request.CertificateExtensions.Add(san.Build());
|
|
|
|
certificate = request.Create(_privateCertificate, DateTimeOffset.Now,
|
|
DateTimeOffset.Now + TimeSpan.FromDays(365), BitConverter.GetBytes(DateTime.Now.ToUnixTimeSeconds()));
|
|
|
|
WritePemFile(certFileName, certificate);
|
|
WritePemFile(keyFileName, rsa);
|
|
|
|
return true;
|
|
}
|
|
|
|
certificate = null;
|
|
return false;
|
|
}
|
|
|
|
|
|
private bool TryLoadCertificate(string distinguishedName, out X509Certificate2? certificate)
|
|
{
|
|
string certFileName = Path.Combine(StoragePath, $"{distinguishedName}.cert.pem");
|
|
string keyFileName = Path.Combine(StoragePath, $"{distinguishedName}.key.pem");
|
|
|
|
if (File.Exists(certFileName) && File.Exists(keyFileName))
|
|
{
|
|
// certificate = new X509Certificate2(X509Certificate2.CreateFromPemFile(certFileName, keyFileName).Export(X509ContentType.Pfx, "alpha"), "alpha");
|
|
certificate = X509Certificate2.CreateFromPemFile(certFileName, keyFileName);
|
|
return true;
|
|
}
|
|
|
|
certificate = null;
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
private void WritePemFile(string pemFileName, X509Certificate2 certificate2, RSA rsa)
|
|
{
|
|
using (var pemFileStream =
|
|
new StreamWriter(new FileStream(pemFileName, FileMode.CreateNew)))
|
|
{
|
|
WritePemFile("CERTIFICATE", certificate2.RawData, pemFileStream);
|
|
WritePemFile("RSA PRIVATE KEY", rsa.ExportRSAPrivateKey(), pemFileStream);
|
|
}
|
|
}
|
|
private void WritePemFile(string pemFileName, X509Certificate2 certificate2)
|
|
{
|
|
using (var pemFileStream =
|
|
new StreamWriter(new FileStream(pemFileName, FileMode.CreateNew)))
|
|
{
|
|
WritePemFile("CERTIFICATE", certificate2.RawData, pemFileStream);
|
|
}
|
|
}
|
|
private void WritePemFile(string pemFileName, RSA rsa)
|
|
{
|
|
using (var pemFileStream =
|
|
new StreamWriter(new FileStream(pemFileName, FileMode.CreateNew)))
|
|
{
|
|
WritePemFile("RSA PRIVATE KEY", rsa.ExportRSAPrivateKey(), pemFileStream);
|
|
}
|
|
}
|
|
|
|
|
|
private static void WritePemFile(string type, byte[] data, TextWriter outputFile)
|
|
{
|
|
outputFile.WriteLine($"-----BEGIN {type}-----");
|
|
outputFile.WriteLine(Convert.ToBase64String(data, Base64FormattingOptions.InsertLineBreaks));
|
|
outputFile.WriteLine($"-----END {type}-----");
|
|
}
|
|
} |