mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-10-26 18:41:18 +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
|
||||
//
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
|
|
@ -33,9 +34,18 @@ namespace WelsonJS.Launcher
|
|||
/// 1) %APPDATA%\{appDataSubdirectory}\{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.
|
||||
/// </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 (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
|
|
@ -60,12 +70,12 @@ namespace WelsonJS.Launcher
|
|||
// 1) %APPDATA% subdirectory
|
||||
string candidate1 = Path.Combine(appDataPath, dllName);
|
||||
triedPaths.Add(candidate1);
|
||||
if (TryLoad(candidate1, logger)) return;
|
||||
if (TryLoad(candidate1, logger, requireSigned, certValidator)) return;
|
||||
|
||||
// 2) Application base directory
|
||||
string candidate2 = Path.Combine(appBaseDirectory, dllName);
|
||||
triedPaths.Add(candidate2);
|
||||
if (TryLoad(candidate2, logger)) return;
|
||||
if (TryLoad(candidate2, logger, requireSigned, certValidator)) return;
|
||||
}
|
||||
|
||||
string message = "Failed to load requested native libraries.\n" +
|
||||
|
|
@ -74,7 +84,11 @@ namespace WelsonJS.Launcher
|
|||
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
|
||||
{
|
||||
|
|
@ -84,6 +98,14 @@ namespace WelsonJS.Launcher
|
|||
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;
|
||||
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)
|
||||
{
|
||||
try
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ namespace WelsonJS.Launcher
|
|||
{
|
||||
internal static class Program
|
||||
{
|
||||
private const string _appDataSubDirectory = "WelsonJS";
|
||||
private static readonly ICompatibleLogger _logger;
|
||||
|
||||
public static Mutex _mutex;
|
||||
|
|
@ -27,9 +26,14 @@ namespace WelsonJS.Launcher
|
|||
_logger = new TraceLogger();
|
||||
|
||||
// load native libraries
|
||||
NativeBootstrap.Init(new string[] {
|
||||
"ChakraCore.dll"
|
||||
}, _appDataSubDirectory, _logger);
|
||||
string appDataSubDirectory = "WelsonJS";
|
||||
bool requireSigned = GetAppConfig("NativeRequireSigned").Equals("true");
|
||||
NativeBootstrap.Init(
|
||||
dllNames: new[] { "ChakraCore.dll" },
|
||||
appDataSubdirectory: appDataSubDirectory,
|
||||
logger: _logger,
|
||||
requireSigned: requireSigned
|
||||
);
|
||||
}
|
||||
|
||||
[STAThread]
|
||||
|
|
|
|||
|
|
@ -286,6 +286,15 @@ namespace WelsonJS.Launcher.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// false과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string NativeRequireSigned {
|
||||
get {
|
||||
return ResourceManager.GetString("NativeRequireSigned", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/gnh1201/welsonjs과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -208,4 +208,7 @@
|
|||
<data name="ChromiumDevToolsTimeout" xml:space="preserve">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name="NativeRequireSigned" xml:space="preserve">
|
||||
<value>false</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -92,7 +92,6 @@
|
|||
<Compile Include="JsNative.cs" />
|
||||
<Compile Include="JsSerializer.cs" />
|
||||
<Compile Include="NativeBootstrap.cs" />
|
||||
<Compile Include="ResourceTools\ImageProxy.cs" />
|
||||
<Compile Include="ResourceTools\IpQuery.cs" />
|
||||
<Compile Include="ResourceTools\Settings.cs" />
|
||||
<Compile Include="ResourceTools\Completion.cs" />
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
<add key="CitiApiKey" value=""/>
|
||||
<add key="CitiApiPrefix" value="https://api.criminalip.io/v1/"/>
|
||||
<add key="DateTimeFormat" value="yyyy-MM-dd HH:mm:ss"/>
|
||||
<add key="NativeRequireSigned" value="false"/>
|
||||
</appSettings>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user