Add PKCS#11-based PDF signing infrastructure
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.
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user