Introduced a cryptographic infrastructure for PDF signing and validation using PKCS#11-based hardware security modules (HSMs) or software tokens. Key changes include: - Added `PdfDigitalSignatureService` for signing PDFs, multi-signature support, and signature validation. - Implemented `Pkcs11ExternalSigner` and `Pkcs11PdfSigningRsa` for PKCS#11-based signing with DevExpress PDF infrastructure. - Added utilities like `Pkcs11SessionRunner`, `Pkcs11InteropBootstrap`, and `Pkcs11ToolBridge` for session management, library initialization, and fallback mechanisms. - Introduced `Pkcs11Options` for managing PKCS#11 configurations. - Updated project dependencies to include `DevExpress.Document.Processor`, `System.Security.Cryptography.Pkcs`, and `Pkcs11Interop`. - Enhanced error handling and fallback support for PKCS#11 operations. These changes enable robust and extensible PDF signing capabilities with detailed signature metadata extraction and validation.
88 lines
2.7 KiB
C#
88 lines
2.7 KiB
C#
using EnvelopeGenerator.Application.Common.Configurations;
|
|
|
|
namespace EnvelopeGenerator.Infrastructure.Crypt.Services;
|
|
|
|
internal static class Pkcs11InteropBootstrap
|
|
{
|
|
private static readonly object Sync = new();
|
|
private static bool Initialized;
|
|
|
|
public static void EnsureLoaded(Pkcs11Options options)
|
|
{
|
|
if (Initialized)
|
|
return;
|
|
|
|
lock (Sync)
|
|
{
|
|
if (Initialized)
|
|
return;
|
|
|
|
EnsureNativeDependencySearchPath(options.LibraryPath);
|
|
|
|
if (!string.IsNullOrWhiteSpace(options.ProxySocket))
|
|
{
|
|
Environment.SetEnvironmentVariable("PKCS11_PROXY_SOCKET", options.ProxySocket);
|
|
Environment.SetEnvironmentVariable("PKCS11_DAEMON_SOCKET", options.ProxySocket);
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(options.ToolPath))
|
|
{
|
|
var toolDir = Path.GetDirectoryName(options.ToolPath);
|
|
if (!string.IsNullOrWhiteSpace(toolDir))
|
|
EnsurePathContains(toolDir);
|
|
}
|
|
|
|
WarmupWithPkcs11Tool(options);
|
|
Initialized = true;
|
|
}
|
|
}
|
|
|
|
private static void WarmupWithPkcs11Tool(Pkcs11Options options)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(options.ToolPath))
|
|
return;
|
|
|
|
if (!File.Exists(options.ToolPath))
|
|
return;
|
|
|
|
var process = new System.Diagnostics.Process
|
|
{
|
|
StartInfo = new System.Diagnostics.ProcessStartInfo
|
|
{
|
|
FileName = options.ToolPath,
|
|
Arguments = $"--module \"{options.LibraryPath}\" -L",
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
CreateNoWindow = true
|
|
}
|
|
};
|
|
|
|
process.Start();
|
|
process.WaitForExit(15000);
|
|
}
|
|
|
|
private static void EnsureNativeDependencySearchPath(string libraryPath)
|
|
{
|
|
var directory = Path.GetDirectoryName(libraryPath);
|
|
if (string.IsNullOrWhiteSpace(directory))
|
|
return;
|
|
|
|
EnsurePathContains(directory);
|
|
}
|
|
|
|
private static void EnsurePathContains(string directory)
|
|
{
|
|
var currentPath = Environment.GetEnvironmentVariable("PATH") ?? string.Empty;
|
|
var entries = currentPath.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
|
if (entries.Any(p => string.Equals(p, directory, StringComparison.OrdinalIgnoreCase)))
|
|
return;
|
|
|
|
var updatedPath = string.IsNullOrWhiteSpace(currentPath)
|
|
? directory
|
|
: directory + ";" + currentPath;
|
|
|
|
Environment.SetEnvironmentVariable("PATH", updatedPath);
|
|
}
|
|
}
|