diff --git a/WelsonJS.Augmented/Catswords.TlsReport/App.config b/WelsonJS.Augmented/Catswords.TlsReport/App.config
new file mode 100644
index 0000000..56efbc7
--- /dev/null
+++ b/WelsonJS.Augmented/Catswords.TlsReport/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WelsonJS.Augmented/Catswords.TlsReport/Catswords.TlsReport.csproj b/WelsonJS.Augmented/Catswords.TlsReport/Catswords.TlsReport.csproj
new file mode 100644
index 0000000..ff98449
--- /dev/null
+++ b/WelsonJS.Augmented/Catswords.TlsReport/Catswords.TlsReport.csproj
@@ -0,0 +1,54 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {05EE55FD-76C6-482E-9886-72EB5BD3C621}
+ Exe
+ Catswords.TlsReport
+ Catswords.TlsReport
+ v4.7.2
+ 512
+ true
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WelsonJS.Augmented/Catswords.TlsReport/Program.cs b/WelsonJS.Augmented/Catswords.TlsReport/Program.cs
new file mode 100644
index 0000000..bc6c5db
--- /dev/null
+++ b/WelsonJS.Augmented/Catswords.TlsReport/Program.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Catswords.TlsReport
+{
+ internal class Program
+ {
+ static void Main(string[] args)
+ {
+ Console.WriteLine("Catswords TLS 1.2 Offline Inspector");
+ Console.WriteLine("https://catswords.com");
+ Console.WriteLine();
+
+ var report = Tls12OfflineInspector.Evaluate();
+ Console.WriteLine(report.ToText());
+ Console.WriteLine();
+ }
+ }
+}
diff --git a/WelsonJS.Augmented/Catswords.TlsReport/Properties/AssemblyInfo.cs b/WelsonJS.Augmented/Catswords.TlsReport/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..afd88d6
--- /dev/null
+++ b/WelsonJS.Augmented/Catswords.TlsReport/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
+// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
+// 이러한 특성 값을 변경하세요.
+[assembly: AssemblyTitle("Catswords.TlsReport")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Catswords.TlsReport")]
+[assembly: AssemblyCopyright("Copyright © 2025")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
+// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
+// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
+[assembly: ComVisible(false)]
+
+// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
+[assembly: Guid("05ee55fd-76c6-482e-9886-72eb5bd3c621")]
+
+// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
+//
+// 주 버전
+// 부 버전
+// 빌드 번호
+// 수정 버전
+//
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/WelsonJS.Augmented/Catswords.TlsReport/Tls12OfflineInspector.cs b/WelsonJS.Augmented/Catswords.TlsReport/Tls12OfflineInspector.cs
new file mode 100644
index 0000000..468cd73
--- /dev/null
+++ b/WelsonJS.Augmented/Catswords.TlsReport/Tls12OfflineInspector.cs
@@ -0,0 +1,755 @@
+// Tls12OfflineInspector.cs (single file)
+// Offline-only TLS 1.2 readiness inspector for Windows.
+// - No network probing / no actual TLS handshake.
+// - Produces structured report with Pass/Info/Warn/Fail items.
+//
+// Example:
+// var report = Tls12OfflineInspector.Evaluate();
+// Console.WriteLine(report.ToText());
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Security.Authentication;
+using System.Security.Principal;
+using Microsoft.Win32;
+
+namespace Catswords.TlsReport
+{
+ public static class Tls12OfflineInspector
+ {
+ // ----------------------------
+ // Public entry point
+ // ----------------------------
+
+ public static Report Evaluate()
+ {
+ var ctx = new Context();
+ var items = new List- ();
+
+ // 0) Environment / runtime surface
+ items.Add(CheckOsVersion(ctx));
+ items.Add(CheckProcessBitness(ctx));
+ items.Add(CheckTls12EnumAvailable(ctx));
+ items.Add(CheckSslProtocolsTls12Available(ctx));
+
+ // 1) OS crypto DLL presence (sanity)
+ items.Add(CheckSystemDllPresence(ctx, "schannel.dll"));
+ items.Add(CheckSystemDllPresence(ctx, "bcrypt.dll"));
+ items.Add(CheckSystemDllPresence(ctx, "crypt32.dll"));
+ items.Add(CheckSystemDllPresence(ctx, "ncrypt.dll"));
+
+ // 2) Schannel protocol policy
+ items.Add(CheckSchannelTls12KeyPresence(ctx));
+ items.Add(CheckSchannelTls12ClientPolicy(ctx));
+ items.Add(CheckSchannelTls12ServerPolicy(ctx));
+ items.Add(CheckLegacyProtocolKeyHints(ctx));
+
+ // 3) WinHTTP defaults / legacy guidance
+ items.Add(CheckWinHttpDefaultSecureProtocols(ctx));
+ items.Add(CheckWinHttpDefaultSecureProtocolsIncludesTls12(ctx));
+
+ // 4) .NET Framework policy keys
+ items.Add(CheckDotNetStrongCrypto(ctx));
+ items.Add(CheckDotNetSystemDefaultTlsVersions(ctx));
+ items.Add(CheckDotNetV2StrongCrypto(ctx));
+ items.Add(CheckDotNetV2SystemDefaultTlsVersions(ctx));
+
+ // 5) Process-level legacy setting
+ items.Add(CheckServicePointManagerProtocol(ctx));
+
+ // 6) Cipher suite policy / crypto hardening
+ items.Add(CheckCipherSuitePolicyKey(ctx));
+ items.Add(CheckCipherSuitePolicyFunctions(ctx));
+ items.Add(CheckSchannelHashesAndKeyExchangeExplicitDisables(ctx));
+ items.Add(CheckSchannelStrongCiphersExplicitDisableHeuristic(ctx));
+
+ // 7) FIPS policy
+ items.Add(CheckFipsPolicy(ctx));
+
+ // 8) Proxy hints
+ items.Add(CheckWinHttpProxyPresence(ctx));
+ items.Add(CheckWinInetUserProxyPresence(ctx));
+
+ // 9) Schannel logging (diagnostics)
+ items.Add(CheckSchannelEventLogging(ctx));
+
+ return BuildReport(items);
+ }
+
+ // ----------------------------
+ // Context
+ // ----------------------------
+
+ private sealed class Context
+ {
+ public Version OsVersion = Environment.OSVersion.Version;
+ public bool Is64BitProcess = (IntPtr.Size == 8);
+ public string SystemDir = Environment.SystemDirectory.TrimEnd('\\');
+ }
+
+ // ----------------------------
+ // Check factories: Pass/Info/Warn/Fail
+ // ----------------------------
+
+ private static Item Pass(string id, string detail) => new Item(id, Level.Pass, detail);
+ private static Item Info(string id, string detail) => new Item(id, Level.Info, detail);
+ private static Item Warn(string id, string detail) => new Item(id, Level.Warn, detail);
+ private static Item Fail(string id, string detail) => new Item(id, Level.Fail, detail);
+
+ // ----------------------------
+ // Checks: Environment / runtime
+ // ----------------------------
+
+ private static Item CheckOsVersion(Context ctx)
+ {
+ string hint = GetWindowsNameHint(ctx.OsVersion);
+
+ if (ctx.OsVersion.Major >= 10)
+ return Info("OS Version", "Windows " + hint + " (" + ctx.OsVersion + "). TLS 1.2 is generally available by default.");
+
+ if (ctx.OsVersion.Major == 6 && ctx.OsVersion.Minor >= 3)
+ return Info("OS Version", "Windows " + hint + " (" + ctx.OsVersion + "). TLS 1.2 exists, but legacy WinHTTP/.NET policy may require updates/registry.");
+
+ return Warn("OS Version", "Windows " + hint + " (" + ctx.OsVersion + "). TLS 1.2 readiness is uncertain on older OS.");
+ }
+
+ private static Item CheckProcessBitness(Context ctx)
+ {
+ return Info("Process Bitness", ctx.Is64BitProcess ? "64-bit process" : "32-bit process");
+ }
+
+ private static Item CheckTls12EnumAvailable(Context ctx)
+ {
+ try
+ {
+ var _ = SecurityProtocolType.Tls12;
+ return Pass("Runtime Enum: SecurityProtocolType.Tls12", "Available.");
+ }
+ catch
+ {
+ return Fail("Runtime Enum: SecurityProtocolType.Tls12", "Not available. Runtime is likely too old.");
+ }
+ }
+
+ private static Item CheckSslProtocolsTls12Available(Context ctx)
+ {
+ try
+ {
+ var _ = SslProtocols.Tls12;
+ return Pass("Runtime Enum: SslProtocols.Tls12", "Available.");
+ }
+ catch
+ {
+ return Fail("Runtime Enum: SslProtocols.Tls12", "Not available. Runtime is likely too old.");
+ }
+ }
+
+ // ----------------------------
+ // Checks: DLL presence
+ // ----------------------------
+
+ private static Item CheckSystemDllPresence(Context ctx, string dll)
+ {
+ string path = ctx.SystemDir + "\\" + dll;
+ bool exists;
+ try { exists = System.IO.File.Exists(path); }
+ catch { exists = false; }
+
+ if (exists) return Pass("System DLL present: " + dll, path);
+ return Fail("System DLL present: " + dll, "Missing: " + path);
+ }
+
+ // ----------------------------
+ // Checks: Schannel protocol policy
+ // ----------------------------
+
+ private static Item CheckSchannelTls12KeyPresence(Context ctx)
+ {
+ const string basePath = @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2";
+ bool clientExists = RegistryKeyExists(Registry.LocalMachine, basePath + @"\Client");
+ bool serverExists = RegistryKeyExists(Registry.LocalMachine, basePath + @"\Server");
+
+ if (clientExists || serverExists)
+ return Info("Schannel TLS 1.2 keys present", "Client=" + clientExists + ", Server=" + serverExists + " (absence is normal on modern Windows).");
+
+ return Info("Schannel TLS 1.2 keys present", "No explicit TLS 1.2 keys found (common on modern Windows; defaults may still enable TLS 1.2).");
+ }
+
+ private static Item CheckSchannelTls12ClientPolicy(Context ctx)
+ {
+ const string k = @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client";
+ var enabled = ReadDwordHKLM(k, "Enabled");
+ var disabledByDefault = ReadDwordHKLM(k, "DisabledByDefault");
+
+ if (enabled == null && disabledByDefault == null)
+ return Info("Schannel TLS 1.2 Client policy", "No explicit policy (common on modern Windows).");
+
+ if (enabled == 0 || disabledByDefault == 1)
+ return Fail("Schannel TLS 1.2 Client policy", "TLS 1.2 Client appears disabled (Enabled=0 or DisabledByDefault=1).");
+
+ if (enabled == 1 && (disabledByDefault == null || disabledByDefault == 0))
+ return Pass("Schannel TLS 1.2 Client policy", "Enabled=1 and DisabledByDefault=0 (or missing).");
+
+ return Warn("Schannel TLS 1.2 Client policy", "Ambiguous: Enabled=" + ToS(enabled) + ", DisabledByDefault=" + ToS(disabledByDefault) + ".");
+ }
+
+ private static Item CheckSchannelTls12ServerPolicy(Context ctx)
+ {
+ const string k = @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server";
+ var enabled = ReadDwordHKLM(k, "Enabled");
+ var disabledByDefault = ReadDwordHKLM(k, "DisabledByDefault");
+
+ if (enabled == null && disabledByDefault == null)
+ return Info("Schannel TLS 1.2 Server policy", "No explicit policy (common on modern Windows).");
+
+ if (enabled == 0 || disabledByDefault == 1)
+ return Warn("Schannel TLS 1.2 Server policy", "TLS 1.2 Server appears disabled (may be intentional if not a server).");
+
+ if (enabled == 1 && (disabledByDefault == null || disabledByDefault == 0))
+ return Pass("Schannel TLS 1.2 Server policy", "Enabled=1 and DisabledByDefault=0 (or missing).");
+
+ return Warn("Schannel TLS 1.2 Server policy", "Ambiguous: Enabled=" + ToS(enabled) + ", DisabledByDefault=" + ToS(disabledByDefault) + ".");
+ }
+
+ private static Item CheckLegacyProtocolKeyHints(Context ctx)
+ {
+ bool tls12ClientKey = RegistryKeyExists(Registry.LocalMachine,
+ @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client");
+
+ bool tls10ClientKey = RegistryKeyExists(Registry.LocalMachine,
+ @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client");
+ bool tls11ClientKey = RegistryKeyExists(Registry.LocalMachine,
+ @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client");
+ bool ssl3ClientKey = RegistryKeyExists(Registry.LocalMachine,
+ @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client");
+
+ if (!tls12ClientKey && (tls10ClientKey || tls11ClientKey || ssl3ClientKey))
+ return Warn("Legacy protocol policy hints", "Found SSL3/TLS1.0/TLS1.1 policy keys while TLS1.2 client key is absent. Review hardening baseline.");
+
+ return Info("Legacy protocol policy hints", "No strong legacy-protocol policy hints detected (presence/absence is not definitive).");
+ }
+
+ // ----------------------------
+ // Checks: WinHTTP defaults
+ // ----------------------------
+
+ private static Item CheckWinHttpDefaultSecureProtocols(Context ctx)
+ {
+ const string k64 = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp";
+ const string k32 = @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp";
+
+ var v64 = ReadDwordHKLM(k64, "DefaultSecureProtocols");
+ var v32 = ReadDwordHKLM(k32, "DefaultSecureProtocols");
+
+ if (v64 == null && v32 == null)
+ return Info("WinHTTP DefaultSecureProtocols", "Not set (normal on modern Windows; may be needed on legacy OS like Win7/2012).");
+
+ return Info("WinHTTP DefaultSecureProtocols", "x64=" + ToHex(v64) + ", x86=" + ToHex(v32));
+ }
+
+ private static Item CheckWinHttpDefaultSecureProtocolsIncludesTls12(Context ctx)
+ {
+ const string k64 = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp";
+ const string k32 = @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp";
+
+ var v64 = ReadDwordHKLM(k64, "DefaultSecureProtocols");
+ var v32 = ReadDwordHKLM(k32, "DefaultSecureProtocols");
+
+ if (v64 == null && v32 == null)
+ return Info("WinHTTP DefaultSecureProtocols includes TLS 1.2", "DefaultSecureProtocols not present (unknown/default).");
+
+ const int TLS12_FLAG = 0x00000800;
+ bool ok64 = v64 != null && (v64.Value & TLS12_FLAG) == TLS12_FLAG;
+ bool ok32 = v32 != null && (v32.Value & TLS12_FLAG) == TLS12_FLAG;
+
+ if (ok64 || ok32)
+ return Pass("WinHTTP DefaultSecureProtocols includes TLS 1.2", "Detected TLS 1.2 flag. x64=" + ToHex(v64) + ", x86=" + ToHex(v32));
+
+ return Warn("WinHTTP DefaultSecureProtocols includes TLS 1.2", "TLS 1.2 flag not detected. x64=" + ToHex(v64) + ", x86=" + ToHex(v32));
+ }
+
+ // ----------------------------
+ // Checks: .NET Framework policy keys
+ // ----------------------------
+
+ private static Item CheckDotNetStrongCrypto(Context ctx)
+ {
+ const string k64 = @"SOFTWARE\Microsoft\.NETFramework\v4.0.30319";
+ const string k32 = @"SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319";
+
+ var v64 = ReadDwordHKLM(k64, "SchUseStrongCrypto");
+ var v32 = ReadDwordHKLM(k32, "SchUseStrongCrypto");
+
+ if (v64 == 1 || v32 == 1)
+ return Pass(".NET SchUseStrongCrypto", "Enabled. x64=" + ToS(v64) + ", x86=" + ToS(v32));
+
+ if (v64 == null && v32 == null)
+ return Info(".NET SchUseStrongCrypto", "Not explicitly set (common on modern OS/.NET).");
+
+ return Warn(".NET SchUseStrongCrypto", "Not set to 1. x64=" + ToS(v64) + ", x86=" + ToS(v32));
+ }
+
+ private static Item CheckDotNetSystemDefaultTlsVersions(Context ctx)
+ {
+ const string k64 = @"SOFTWARE\Microsoft\.NETFramework\v4.0.30319";
+ const string k32 = @"SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319";
+
+ var v64 = ReadDwordHKLM(k64, "SystemDefaultTlsVersions");
+ var v32 = ReadDwordHKLM(k32, "SystemDefaultTlsVersions");
+
+ if (v64 == 1 || v32 == 1)
+ return Pass(".NET SystemDefaultTlsVersions", "Enabled. x64=" + ToS(v64) + ", x86=" + ToS(v32));
+
+ if (v64 == null && v32 == null)
+ return Info(".NET SystemDefaultTlsVersions", "Not explicitly set (common on modern OS/.NET).");
+
+ return Warn(".NET SystemDefaultTlsVersions", "Not set to 1. x64=" + ToS(v64) + ", x86=" + ToS(v32));
+ }
+
+ private static Item CheckDotNetV2StrongCrypto(Context ctx)
+ {
+ // .NET 2.0/3.0/3.5 line uses v2.0.50727.
+ // On many systems, these values might not exist; treat as Info/Warn.
+ const string k64 = @"SOFTWARE\Microsoft\.NETFramework\v2.0.50727";
+ const string k32 = @"SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v2.0.50727";
+
+ var v64 = ReadDwordHKLM(k64, "SchUseStrongCrypto");
+ var v32 = ReadDwordHKLM(k32, "SchUseStrongCrypto");
+
+ if (v64 == 1 || v32 == 1)
+ return Pass(".NET(v2.0.50727) SchUseStrongCrypto", "Enabled. x64=" + ToS(v64) + ", x86=" + ToS(v32));
+
+ if (v64 == null && v32 == null)
+ {
+ // On many modern OS, this isn't set. For legacy .NET apps, warn (because default can be TLS 1.0).
+ return Info(".NET(v2.0.50727) SchUseStrongCrypto", "Not explicitly set (common). Legacy .NET 2.0/3.5 apps may still default to older protocols.");
+ }
+
+ return Warn(".NET(v2.0.50727) SchUseStrongCrypto", "Not set to 1. x64=" + ToS(v64) + ", x86=" + ToS(v32));
+ }
+
+ private static Item CheckDotNetV2SystemDefaultTlsVersions(Context ctx)
+ {
+ // .NET 2.0/3.0/3.5 line uses v2.0.50727.
+ const string k64 = @"SOFTWARE\Microsoft\.NETFramework\v2.0.50727";
+ const string k32 = @"SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v2.0.50727";
+
+ var v64 = ReadDwordHKLM(k64, "SystemDefaultTlsVersions");
+ var v32 = ReadDwordHKLM(k32, "SystemDefaultTlsVersions");
+
+ if (v64 == 1 || v32 == 1)
+ return Pass(".NET(v2.0.50727) SystemDefaultTlsVersions", "Enabled. x64=" + ToS(v64) + ", x86=" + ToS(v32));
+
+ if (v64 == null && v32 == null)
+ {
+ // Same rationale: not always present, but matters for legacy CLR apps.
+ return Info(".NET(v2.0.50727) SystemDefaultTlsVersions", "Not explicitly set (common). Legacy .NET 2.0/3.5 apps may not follow OS default TLS without updates/keys.");
+ }
+
+ return Warn(".NET(v2.0.50727) SystemDefaultTlsVersions", "Not set to 1. x64=" + ToS(v64) + ", x86=" + ToS(v32));
+ }
+
+ // ----------------------------
+ // Checks: Process-level (legacy)
+ // ----------------------------
+
+ private static Item CheckServicePointManagerProtocol(Context ctx)
+ {
+ try
+ {
+ var current = ServicePointManager.SecurityProtocol;
+ bool hasTls12 = (current & SecurityProtocolType.Tls12) == SecurityProtocolType.Tls12;
+
+ if (hasTls12)
+ return Pass("ServicePointManager.SecurityProtocol includes TLS 1.2", current.ToString());
+
+ return Info("ServicePointManager.SecurityProtocol includes TLS 1.2",
+ current.ToString() + " (process-level; can be set at runtime for legacy stacks).");
+ }
+ catch (Exception ex)
+ {
+ return Warn("ServicePointManager.SecurityProtocol includes TLS 1.2",
+ "Could not read: " + ex.GetType().Name + ": " + ex.Message);
+ }
+ }
+
+ // ----------------------------
+ // Checks: Cipher suite policy / crypto hardening
+ // ----------------------------
+
+ private static Item CheckCipherSuitePolicyKey(Context ctx)
+ {
+ const string k = @"SOFTWARE\Policies\Microsoft\Cryptography\Configuration\SSL\00010002";
+ bool exists = RegistryKeyExists(Registry.LocalMachine, k);
+
+ if (!exists)
+ return Info("Cipher suite policy key", "No explicit policy key found (default cipher suite selection applies).");
+
+ return Info("Cipher suite policy key", "Policy key exists (cipher suites may be explicitly controlled).");
+ }
+
+ private static Item CheckCipherSuitePolicyFunctions(Context ctx)
+ {
+ const string k = @"SOFTWARE\Policies\Microsoft\Cryptography\Configuration\SSL\00010002";
+ if (!RegistryKeyExists(Registry.LocalMachine, k))
+ return Info("Cipher suite policy Functions", "Policy key not present.");
+
+ var funcs = ReadMultiStringHKLM(k, "Functions");
+ if (funcs == null)
+ return Warn("Cipher suite policy Functions", "Functions value not readable or not set.");
+ if (funcs.Length == 0)
+ return Fail("Cipher suite policy Functions", "Functions list is empty. This can block TLS handshakes.");
+ return Info("Cipher suite policy Functions", "Functions count=" + funcs.Length);
+ }
+
+ private static Item CheckSchannelHashesAndKeyExchangeExplicitDisables(Context ctx)
+ {
+ var checks = new (string key, string label)[]
+ {
+ (@"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes\SHA", "SHA"),
+ (@"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes\SHA256", "SHA256"),
+ (@"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes\SHA384", "SHA384"),
+ (@"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\PKCS", "RSA (PKCS)"),
+ (@"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\ECDH", "ECDH"),
+ (@"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman", "DH"),
+ };
+
+ var disabled = new List();
+ foreach (var c in checks)
+ {
+ var enabled = ReadDwordHKLM(c.key, "Enabled");
+ if (enabled == 0) disabled.Add(c.label);
+ }
+
+ if (disabled.Count > 0)
+ return Warn("Schannel Hash/KeyExchange disables", "Explicitly disabled: " + string.Join(", ", disabled));
+
+ return Info("Schannel Hash/KeyExchange disables", "No explicit disables detected for common Hash/KeyExchange components.");
+ }
+
+ private static Item CheckSchannelStrongCiphersExplicitDisableHeuristic(Context ctx)
+ {
+ var aesKeys = new[]
+ {
+ @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\AES 128/128",
+ @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\AES 256/256",
+ };
+
+ var disabled = new List();
+ foreach (var k in aesKeys)
+ {
+ var enabled = ReadDwordHKLM(k, "Enabled");
+ if (enabled == 0) disabled.Add(k.Split('\\').Last());
+ }
+
+ if (disabled.Count > 0)
+ return Warn("Schannel AES ciphers explicitly disabled", "Disabled: " + string.Join(", ", disabled));
+
+ return Info("Schannel AES ciphers explicitly disabled", "No explicit AES cipher disable detected (absence is normal).");
+ }
+
+ // ----------------------------
+ // Checks: FIPS policy
+ // ----------------------------
+
+ private static Item CheckFipsPolicy(Context ctx)
+ {
+ const string k = @"SYSTEM\CurrentControlSet\Control\Lsa\FipsAlgorithmPolicy";
+ var enabled = ReadDwordHKLM(k, "Enabled");
+
+ if (enabled == 1)
+ return Warn("FIPS policy", "Enabled=1. Crypto/TLS behavior may change depending on libraries and cipher suite policies.");
+ if (enabled == 0)
+ return Info("FIPS policy", "Enabled=0.");
+ return Info("FIPS policy", "Not set (unknown/default).");
+ }
+
+ // ----------------------------
+ // Checks: Proxy hints
+ // ----------------------------
+
+ private static Item CheckWinHttpProxyPresence(Context ctx)
+ {
+ const string k = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Connections";
+ var bytes = ReadBinaryHKLM(k, "WinHttpSettings");
+
+ if (bytes == null || bytes.Length == 0)
+ return Info("WinHTTP proxy presence", "WinHttpSettings not found (no evidence of WinHTTP proxy config).");
+
+ return Info("WinHTTP proxy presence", "WinHttpSettings exists (proxy may be configured; can affect certs/endpoints).");
+ }
+
+ private static Item CheckWinInetUserProxyPresence(Context ctx)
+ {
+ const string k = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings";
+ var proxyEnable = ReadDwordHKCU(k, "ProxyEnable");
+ var proxyServer = ReadStringHKCU(k, "ProxyServer");
+
+ if (proxyEnable == 1 && !string.IsNullOrEmpty(proxyServer))
+ return Info("WinINet user proxy", "ProxyEnable=1, ProxyServer=" + proxyServer);
+
+ return Info("WinINet user proxy", "No obvious per-user proxy configuration detected.");
+ }
+
+ // ----------------------------
+ // Checks: Schannel event logging
+ // ----------------------------
+
+ private static Item CheckSchannelEventLogging(Context ctx)
+ {
+ const string k = @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL";
+ var v = ReadDwordHKLM(k, "EventLogging");
+
+ if (v == null)
+ return Info("Schannel EventLogging", "Not set (default).");
+
+ return Info("Schannel EventLogging", "EventLogging=" + v + " (enables Schannel logs in Event Viewer).");
+ }
+
+ // ----------------------------
+ // Report build
+ // ----------------------------
+
+ private static Report BuildReport(List
- items)
+ {
+ bool tls12ClientDisabled = items.Any(i => i.Id == "Schannel TLS 1.2 Client policy" && i.Level == Level.Fail);
+ bool missingCryptoDll = items.Any(i => i.Id.StartsWith("System DLL present: ", StringComparison.OrdinalIgnoreCase) && i.Level == Level.Fail);
+ bool cipherPolicyEmpty = items.Any(i => i.Id == "Cipher suite policy Functions" && i.Level == Level.Fail);
+
+ bool anyWarn = items.Any(i => i.Level == Level.Warn);
+
+ Readiness readiness;
+ if (tls12ClientDisabled || missingCryptoDll || cipherPolicyEmpty)
+ readiness = Readiness.NotReady;
+ else if (anyWarn)
+ readiness = Readiness.ProbablyReadyButRisky;
+ else
+ readiness = Readiness.ProbablyReady;
+
+ var rec = BuildRecommendations(items, readiness);
+ return new Report(readiness, rec, items);
+ }
+
+ private static string[] BuildRecommendations(List
- items, Readiness readiness)
+ {
+ var rec = new List();
+
+ bool tls12ClientDisabled = items.Any(i => i.Id == "Schannel TLS 1.2 Client policy" && i.Level == Level.Fail);
+ bool winhttpTls12FlagWarn = items.Any(i => i.Id == "WinHTTP DefaultSecureProtocols includes TLS 1.2" && i.Level == Level.Warn);
+ bool dotnetWarn =
+ items.Any(i => i.Id == ".NET SchUseStrongCrypto" && i.Level == Level.Warn) ||
+ items.Any(i => i.Id == ".NET SystemDefaultTlsVersions" && i.Level == Level.Warn);
+ bool cipherPolicyEmpty = items.Any(i => i.Id == "Cipher suite policy Functions" && i.Level == Level.Fail);
+ bool aesDisabled = items.Any(i => i.Id == "Schannel AES ciphers explicitly disabled" && i.Level == Level.Warn);
+ bool fipsEnabled = items.Any(i => i.Id == "FIPS policy" && i.Level == Level.Warn);
+
+ if (tls12ClientDisabled)
+ rec.Add("TLS 1.2 is explicitly disabled in Schannel Client policy. Enable it (Enabled=1, DisabledByDefault=0) or remove the disabling baseline.");
+
+ if (cipherPolicyEmpty)
+ rec.Add("Cipher suite policy exists but Functions list is empty. Populate cipher suites or remove the policy; otherwise TLS handshakes will fail.");
+
+ if (winhttpTls12FlagWarn)
+ rec.Add("WinHTTP DefaultSecureProtocols does not show TLS 1.2 flag. On legacy OS, apply KB3140245 guidance and include TLS 1.2 in DefaultSecureProtocols.");
+
+ if (dotnetWarn)
+ rec.Add("For legacy .NET Framework apps, consider setting SchUseStrongCrypto=1 and SystemDefaultTlsVersions=1 under .NETFramework\\v4.0.30319 (both 64/32-bit).");
+
+ if (aesDisabled)
+ rec.Add("AES cipher(s) are explicitly disabled in Schannel. Modern TLS 1.2 endpoints typically require AES; re-enable unless you have a specific policy reason.");
+
+ if (fipsEnabled)
+ rec.Add("FIPS policy is enabled. Ensure your cipher suite policy and TLS stacks remain compatible with FIPS constraints.");
+
+ if (rec.Count == 0)
+ {
+ if (readiness == Readiness.ProbablyReady)
+ rec.Add("No offline red flags detected. TLS 1.2 is probably supported by OS/runtime policy.");
+ else
+ rec.Add("Some offline hints suggest risk. If failures occur, review Schannel policy, cipher suite policy, WinHTTP defaults, and .NET strong crypto settings.");
+ }
+
+ return rec.ToArray();
+ }
+
+ // ----------------------------
+ // Models
+ // ----------------------------
+
+ public enum Level { Pass, Info, Warn, Fail }
+ public enum Readiness { ProbablyReady, ProbablyReadyButRisky, NotReady }
+
+ public sealed class Item
+ {
+ public string Id { get; }
+ public Level Level { get; }
+ public string Detail { get; }
+
+ public Item(string id, Level level, string detail)
+ {
+ Id = id ?? "";
+ Level = level;
+ Detail = detail ?? "";
+ }
+
+ public override string ToString() => "[" + Level + "] " + Id + " - " + Detail;
+ }
+
+ public sealed class Report
+ {
+ public Readiness Readiness { get; }
+ public IReadOnlyList Recommendations { get; }
+ public IReadOnlyList
- Items { get; }
+
+ public Report(Readiness readiness, IReadOnlyList recommendations, IReadOnlyList
- items)
+ {
+ Readiness = readiness;
+ Recommendations = recommendations ?? Array.Empty();
+ Items = items ?? Array.Empty
- ();
+ }
+
+ public string ToText()
+ {
+ var lines = new List();
+ lines.Add("TLS 1.2 Offline Readiness: " + Readiness);
+ lines.Add("");
+
+ if (Recommendations.Count > 0)
+ {
+ lines.Add("Recommendations:");
+ for (int i = 0; i < Recommendations.Count; i++)
+ lines.Add(" - " + Recommendations[i]);
+ lines.Add("");
+ }
+
+ lines.Add("Checks:");
+ foreach (var item in Items)
+ lines.Add(" " + item.ToString());
+
+ return string.Join(Environment.NewLine, lines.ToArray());
+ }
+ }
+
+ // ----------------------------
+ // Registry helpers
+ // ----------------------------
+
+ private static bool RegistryKeyExists(RegistryKey root, string subKeyPath)
+ {
+ try { using (var k = root.OpenSubKey(subKeyPath, false)) return k != null; }
+ catch { return false; }
+ }
+
+ private static int? ReadDwordHKLM(string subKeyPath, string valueName)
+ {
+ try
+ {
+ using (var key = Registry.LocalMachine.OpenSubKey(subKeyPath, false))
+ {
+ if (key == null) return null;
+ object v = key.GetValue(valueName, null);
+ if (v == null) return null;
+ if (v is int i) return i;
+ if (v is byte[] b && b.Length >= 4) return BitConverter.ToInt32(b, 0);
+ return null;
+ }
+ }
+ catch { return null; }
+ }
+
+ private static string[] ReadMultiStringHKLM(string subKeyPath, string valueName)
+ {
+ try
+ {
+ using (var key = Registry.LocalMachine.OpenSubKey(subKeyPath, false))
+ {
+ if (key == null) return null;
+ return key.GetValue(valueName, null) as string[];
+ }
+ }
+ catch { return null; }
+ }
+
+ private static byte[] ReadBinaryHKLM(string subKeyPath, string valueName)
+ {
+ try
+ {
+ using (var key = Registry.LocalMachine.OpenSubKey(subKeyPath, false))
+ {
+ if (key == null) return null;
+ return key.GetValue(valueName, null) as byte[];
+ }
+ }
+ catch { return null; }
+ }
+
+ private static int? ReadDwordHKCU(string subKeyPath, string valueName)
+ {
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(subKeyPath, false))
+ {
+ if (key == null) return null;
+ object v = key.GetValue(valueName, null);
+ if (v == null) return null;
+ if (v is int i) return i;
+ if (v is byte[] b && b.Length >= 4) return BitConverter.ToInt32(b, 0);
+ return null;
+ }
+ }
+ catch { return null; }
+ }
+
+ private static string ReadStringHKCU(string subKeyPath, string valueName)
+ {
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(subKeyPath, false))
+ {
+ if (key == null) return null;
+ return key.GetValue(valueName, null) as string;
+ }
+ }
+ catch { return null; }
+ }
+
+ // ----------------------------
+ // Formatting helpers
+ // ----------------------------
+
+ private static string ToS(int? v) => v.HasValue ? v.Value.ToString() : "null";
+ private static string ToHex(int? v) => v.HasValue ? ("0x" + v.Value.ToString("X")) : "null";
+
+ private static string GetWindowsNameHint(Version v)
+ {
+ if (v.Major >= 10) return "10/11+";
+ if (v.Major == 6 && v.Minor == 3) return "8.1/2012 R2";
+ if (v.Major == 6 && v.Minor == 2) return "8/2012";
+ if (v.Major == 6 && v.Minor == 1) return "7/2008 R2";
+ if (v.Major == 6 && v.Minor == 0) return "Vista/2008";
+ return "Unknown";
+ }
+
+ // ----------------------------
+ // Optional: Admin check (extension point)
+ // ----------------------------
+
+ public static bool IsAdministrator()
+ {
+ try
+ {
+ using (var identity = WindowsIdentity.GetCurrent())
+ {
+ var principal = new WindowsPrincipal(identity);
+ return principal.IsInRole(WindowsBuiltInRole.Administrator);
+ }
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/WelsonJS.Augmented/WelsonJS.Augmented.sln b/WelsonJS.Augmented/WelsonJS.Augmented.sln
index 74d1463..ef50abd 100644
--- a/WelsonJS.Augmented/WelsonJS.Augmented.sln
+++ b/WelsonJS.Augmented/WelsonJS.Augmented.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.8.34322.80
+# Visual Studio Version 18
+VisualStudioVersion = 18.1.11312.151 d18.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WelsonJS.Toolkit", "WelsonJS.Toolkit\WelsonJS.Toolkit.csproj", "{D6007282-B4F7-4694-AC67-BB838D91B77A}"
EndProject
@@ -19,6 +19,8 @@ Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "WelsonJS.Cryptography.Test"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Catswords.Phantomizer", "Catswords.Phantomizer\Catswords.Phantomizer.csproj", "{59C67003-C14E-4703-927F-318BFF15F903}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Catswords.TlsReport", "Catswords.TlsReport\Catswords.TlsReport.csproj", "{05EE55FD-76C6-482E-9886-72EB5BD3C621}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -91,6 +93,14 @@ Global
{59C67003-C14E-4703-927F-318BFF15F903}.Release|Any CPU.Build.0 = Release|Any CPU
{59C67003-C14E-4703-927F-318BFF15F903}.Release|x86.ActiveCfg = Release|Any CPU
{59C67003-C14E-4703-927F-318BFF15F903}.Release|x86.Build.0 = Release|Any CPU
+ {05EE55FD-76C6-482E-9886-72EB5BD3C621}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {05EE55FD-76C6-482E-9886-72EB5BD3C621}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {05EE55FD-76C6-482E-9886-72EB5BD3C621}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {05EE55FD-76C6-482E-9886-72EB5BD3C621}.Debug|x86.Build.0 = Debug|Any CPU
+ {05EE55FD-76C6-482E-9886-72EB5BD3C621}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {05EE55FD-76C6-482E-9886-72EB5BD3C621}.Release|Any CPU.Build.0 = Release|Any CPU
+ {05EE55FD-76C6-482E-9886-72EB5BD3C621}.Release|x86.ActiveCfg = Release|Any CPU
+ {05EE55FD-76C6-482E-9886-72EB5BD3C621}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE