mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-10-27 02:51:17 +00:00
Add optional Authenticode signature validation for native DLLs
Enhanced NativeBootstrap to support optional Authenticode signature validation and custom certificate validators when loading native libraries. Added 'NativeRequireSigned' configuration to app.config and resources, allowing signature enforcement to be toggled. Updated Program.cs to use the new option during initialization.
This commit is contained in:
parent
87020d35ac
commit
2db47bca9a
|
|
@ -4,10 +4,11 @@
|
||||||
// https://github.com/gnh1201/welsonjs
|
// https://github.com/gnh1201/welsonjs
|
||||||
//
|
//
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Collections.Generic;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
|
||||||
namespace WelsonJS.Launcher
|
namespace WelsonJS.Launcher
|
||||||
{
|
{
|
||||||
|
|
@ -33,9 +34,18 @@ namespace WelsonJS.Launcher
|
||||||
/// 1) %APPDATA%\{appDataSubdirectory}\{dllName}
|
/// 1) %APPDATA%\{appDataSubdirectory}\{dllName}
|
||||||
/// 2) Application base directory\{dllName}
|
/// 2) Application base directory\{dllName}
|
||||||
///
|
///
|
||||||
|
/// Signatures:
|
||||||
|
/// - requireSigned = true : Only loads DLLs with a valid Authenticode chain.
|
||||||
|
/// - certValidator != null : Additional custom validation (e.g., pinning).
|
||||||
|
///
|
||||||
/// Must be called before any P/Invoke usage.
|
/// Must be called before any P/Invoke usage.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void Init(IEnumerable<string> dllNames, string appDataSubdirectory, ICompatibleLogger logger)
|
public static void Init(
|
||||||
|
IEnumerable<string> dllNames,
|
||||||
|
string appDataSubdirectory,
|
||||||
|
ICompatibleLogger logger,
|
||||||
|
bool requireSigned = false,
|
||||||
|
Func<X509Certificate2, bool> certValidator = null)
|
||||||
{
|
{
|
||||||
if (dllNames == null) throw new ArgumentNullException(nameof(dllNames));
|
if (dllNames == null) throw new ArgumentNullException(nameof(dllNames));
|
||||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||||
|
|
@ -60,12 +70,12 @@ namespace WelsonJS.Launcher
|
||||||
// 1) %APPDATA% subdirectory
|
// 1) %APPDATA% subdirectory
|
||||||
string candidate1 = Path.Combine(appDataPath, dllName);
|
string candidate1 = Path.Combine(appDataPath, dllName);
|
||||||
triedPaths.Add(candidate1);
|
triedPaths.Add(candidate1);
|
||||||
if (TryLoad(candidate1, logger)) return;
|
if (TryLoad(candidate1, logger, requireSigned, certValidator)) return;
|
||||||
|
|
||||||
// 2) Application base directory
|
// 2) Application base directory
|
||||||
string candidate2 = Path.Combine(appBaseDirectory, dllName);
|
string candidate2 = Path.Combine(appBaseDirectory, dllName);
|
||||||
triedPaths.Add(candidate2);
|
triedPaths.Add(candidate2);
|
||||||
if (TryLoad(candidate2, logger)) return;
|
if (TryLoad(candidate2, logger, requireSigned, certValidator)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string message = "Failed to load requested native libraries.\n" +
|
string message = "Failed to load requested native libraries.\n" +
|
||||||
|
|
@ -74,7 +84,11 @@ namespace WelsonJS.Launcher
|
||||||
throw new FileNotFoundException(message);
|
throw new FileNotFoundException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryLoad(string fullPath, ICompatibleLogger logger)
|
private static bool TryLoad(
|
||||||
|
string fullPath,
|
||||||
|
ICompatibleLogger logger,
|
||||||
|
bool requireSigned,
|
||||||
|
Func<X509Certificate2, bool> certValidator)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -84,6 +98,14 @@ namespace WelsonJS.Launcher
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Optional signature validation
|
||||||
|
if (!ValidateSignatureIfRequired(fullPath, requireSigned, certValidator, logger))
|
||||||
|
{
|
||||||
|
// If requireSigned=false we never reach here (it would return true).
|
||||||
|
logger.Warn($"Signature validation failed: {fullPath}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
string directoryPath = Path.GetDirectoryName(fullPath) ?? AppContext.BaseDirectory;
|
string directoryPath = Path.GetDirectoryName(fullPath) ?? AppContext.BaseDirectory;
|
||||||
if (!TryRegisterSearchDirectory(directoryPath, logger))
|
if (!TryRegisterSearchDirectory(directoryPath, logger))
|
||||||
{
|
{
|
||||||
|
|
@ -109,6 +131,81 @@ namespace WelsonJS.Launcher
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If requireSigned=false, returns true (no check).
|
||||||
|
/// If requireSigned=true, verifies Authenticode chain and optional custom validator.
|
||||||
|
/// </summary>
|
||||||
|
private static bool ValidateSignatureIfRequired(
|
||||||
|
string path,
|
||||||
|
bool requireSigned,
|
||||||
|
Func<X509Certificate2, bool> certValidator,
|
||||||
|
ICompatibleLogger logger)
|
||||||
|
{
|
||||||
|
if (!requireSigned)
|
||||||
|
{
|
||||||
|
// No signature requirement: allow loading regardless of signature.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Throws on unsigned files.
|
||||||
|
var baseCert = X509Certificate.CreateFromSignedFile(path);
|
||||||
|
if (baseCert == null)
|
||||||
|
{
|
||||||
|
logger.Warn("No certificate extracted from file.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cert = new X509Certificate2(baseCert);
|
||||||
|
|
||||||
|
var chain = new X509Chain
|
||||||
|
{
|
||||||
|
ChainPolicy =
|
||||||
|
{
|
||||||
|
RevocationMode = X509RevocationMode.Online,
|
||||||
|
RevocationFlag = X509RevocationFlag.ExcludeRoot,
|
||||||
|
VerificationFlags = X509VerificationFlags.NoFlag,
|
||||||
|
VerificationTime = DateTime.UtcNow
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool chainOk = chain.Build(cert);
|
||||||
|
if (!chainOk)
|
||||||
|
{
|
||||||
|
foreach (var status in chain.ChainStatus)
|
||||||
|
logger.Warn($"Cert chain status: {status.Status} - {status.StatusInformation?.Trim()}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional extra validation, e.g. thumbprint or subject pinning.
|
||||||
|
if (certValidator != null)
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
try { ok = certValidator(cert); }
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Warn($"Custom certificate validator threw: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
logger.Warn("Custom certificate validator rejected the certificate.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info($"Signature validated. Subject='{cert.Subject}', Thumbprint={cert.Thumbprint}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Warn($"Signature check failed: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static bool TryRegisterSearchDirectory(string directoryPath, ICompatibleLogger logger)
|
private static bool TryRegisterSearchDirectory(string directoryPath, ICompatibleLogger logger)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ namespace WelsonJS.Launcher
|
||||||
{
|
{
|
||||||
internal static class Program
|
internal static class Program
|
||||||
{
|
{
|
||||||
private const string _appDataSubDirectory = "WelsonJS";
|
|
||||||
private static readonly ICompatibleLogger _logger;
|
private static readonly ICompatibleLogger _logger;
|
||||||
|
|
||||||
public static Mutex _mutex;
|
public static Mutex _mutex;
|
||||||
|
|
@ -27,9 +26,14 @@ namespace WelsonJS.Launcher
|
||||||
_logger = new TraceLogger();
|
_logger = new TraceLogger();
|
||||||
|
|
||||||
// load native libraries
|
// load native libraries
|
||||||
NativeBootstrap.Init(new string[] {
|
string appDataSubDirectory = "WelsonJS";
|
||||||
"ChakraCore.dll"
|
bool requireSigned = GetAppConfig("NativeRequireSigned").Equals("true");
|
||||||
}, _appDataSubDirectory, _logger);
|
NativeBootstrap.Init(
|
||||||
|
dllNames: new[] { "ChakraCore.dll" },
|
||||||
|
appDataSubdirectory: appDataSubDirectory,
|
||||||
|
logger: _logger,
|
||||||
|
requireSigned: requireSigned
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
|
|
|
||||||
|
|
@ -286,6 +286,15 @@ namespace WelsonJS.Launcher.Properties {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// false과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
|
/// </summary>
|
||||||
|
internal static string NativeRequireSigned {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("NativeRequireSigned", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// https://github.com/gnh1201/welsonjs과(와) 유사한 지역화된 문자열을 찾습니다.
|
/// https://github.com/gnh1201/welsonjs과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -208,4 +208,7 @@
|
||||||
<data name="ChromiumDevToolsTimeout" xml:space="preserve">
|
<data name="ChromiumDevToolsTimeout" xml:space="preserve">
|
||||||
<value>5</value>
|
<value>5</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="NativeRequireSigned" xml:space="preserve">
|
||||||
|
<value>false</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -92,7 +92,6 @@
|
||||||
<Compile Include="JsNative.cs" />
|
<Compile Include="JsNative.cs" />
|
||||||
<Compile Include="JsSerializer.cs" />
|
<Compile Include="JsSerializer.cs" />
|
||||||
<Compile Include="NativeBootstrap.cs" />
|
<Compile Include="NativeBootstrap.cs" />
|
||||||
<Compile Include="ResourceTools\ImageProxy.cs" />
|
|
||||||
<Compile Include="ResourceTools\IpQuery.cs" />
|
<Compile Include="ResourceTools\IpQuery.cs" />
|
||||||
<Compile Include="ResourceTools\Settings.cs" />
|
<Compile Include="ResourceTools\Settings.cs" />
|
||||||
<Compile Include="ResourceTools\Completion.cs" />
|
<Compile Include="ResourceTools\Completion.cs" />
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
<add key="CitiApiKey" value=""/>
|
<add key="CitiApiKey" value=""/>
|
||||||
<add key="CitiApiPrefix" value="https://api.criminalip.io/v1/"/>
|
<add key="CitiApiPrefix" value="https://api.criminalip.io/v1/"/>
|
||||||
<add key="DateTimeFormat" value="yyyy-MM-dd HH:mm:ss"/>
|
<add key="DateTimeFormat" value="yyyy-MM-dd HH:mm:ss"/>
|
||||||
|
<add key="NativeRequireSigned" value="false"/>
|
||||||
</appSettings>
|
</appSettings>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user