Files
DocumentService/DocumentService.Infrastructure.Crypt/Services/Pkcs11ToolBridge.cs
TekH 5e7652ef88 Refactor and rename to DocumentService
Renamed namespaces and projects from DocumentOperator to DocumentService, updating all references accordingly. Refactored PdfSignatureAppearanceDto and related enums to use properties with init accessors for improved clarity. Removed and re-added IPkcs11SelfTestStatusProvider with updated namespace. Simplified dependency injection by removing DocumentOperatorApplication registration. Updated appsettings.json with a specific AssetsRootPath. Incremented version numbers in project files for a new release. Introduced PdfSignatureClient and IPdfSignatureClient for PDF digital-signing operations. Updated project files to use newer Microsoft.Extensions package versions. Removed all DocumentOperator references, completing the transition to DocumentService. Added new DTOs and enums for PDF signature options and appearance.
2026-10-25 18:49:08 +01:00

148 lines
4.4 KiB
C#

using DocumentService.Application.Common.Configuration;
using System.Diagnostics;
using System.Security.Cryptography;
namespace DocumentService.Infrastructure.Crypt.Services;
internal static class Pkcs11ToolBridge
{
public static bool IsAvailable(Pkcs11Options options)
{
return !string.IsNullOrWhiteSpace(options.ResolvedToolPath) && File.Exists(options.ResolvedToolPath);
}
public static byte[] ReadCertificateBytes(Pkcs11Options options)
{
EnsureAvailable(options);
var outputFile = Path.Combine(Path.GetTempPath(), $"pkcs11-cert-{Guid.NewGuid():N}.der");
try
{
var args = CreateBaseArgs(options);
args.Add("--read-object");
args.Add("--type");
args.Add("cert");
args.Add("--label");
args.Add(options.CertificateLabel);
args.Add("--output-file");
args.Add(outputFile);
Execute(options, args);
return File.ReadAllBytes(outputFile);
}
finally
{
DeleteIfExists(outputFile);
}
}
public static byte[] SignDigestInfo(Pkcs11Options options, byte[] digestInfo)
{
EnsureAvailable(options);
var inputFile = Path.Combine(Path.GetTempPath(), $"pkcs11-sign-in-{Guid.NewGuid():N}.bin");
var outputFile = Path.Combine(Path.GetTempPath(), $"pkcs11-sign-out-{Guid.NewGuid():N}.bin");
try
{
File.WriteAllBytes(inputFile, digestInfo);
var args = CreateBaseArgs(options);
args.Add("--sign");
args.Add("--mechanism");
args.Add("RSA-PKCS");
args.Add("--type");
args.Add("privkey");
args.Add("--label");
args.Add(options.PrivateKeyLabel);
args.Add("--input-file");
args.Add(inputFile);
args.Add("--output-file");
args.Add(outputFile);
Execute(options, args);
return File.ReadAllBytes(outputFile);
}
finally
{
DeleteIfExists(inputFile);
DeleteIfExists(outputFile);
}
}
private static List<string> CreateBaseArgs(Pkcs11Options options)
{
var args = new List<string>
{
"--module",
options.ResolvedLibraryPath,
"--login",
"--pin",
options.UserPin
};
if (options.SlotId.HasValue)
{
args.Add("--slot");
args.Add(options.SlotId.Value.ToString());
}
else if (!string.IsNullOrWhiteSpace(options.TokenLabel))
{
args.Add("--token-label");
args.Add(options.TokenLabel);
}
return args;
}
private static void Execute(Pkcs11Options options, IReadOnlyList<string> arguments)
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = options.ResolvedToolPath!,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
}
};
foreach (var argument in arguments)
process.StartInfo.ArgumentList.Add(argument);
if (!string.IsNullOrWhiteSpace(options.ProxySocket))
{
process.StartInfo.Environment["PKCS11_PROXY_SOCKET"] = options.ProxySocket;
process.StartInfo.Environment["PKCS11_DAEMON_SOCKET"] = options.ProxySocket;
}
process.Start();
string stdOut = process.StandardOutput.ReadToEnd();
string stdErr = process.StandardError.ReadToEnd();
if (!process.WaitForExit(30000))
{
try { process.Kill(entireProcessTree: true); } catch { }
throw new TimeoutException($"pkcs11-tool timed out. Args: {string.Join(' ', process.StartInfo.ArgumentList)}");
}
if (process.ExitCode != 0)
throw new InvalidOperationException($"pkcs11-tool failed with exit code {process.ExitCode}. StdOut: {stdOut} StdErr: {stdErr}");
}
private static void EnsureAvailable(Pkcs11Options options)
{
if (!IsAvailable(options))
throw new InvalidOperationException("pkcs11-tool is not available at resolved pkcs11 assets path.");
}
private static void DeleteIfExists(string path)
{
if (File.Exists(path))
File.Delete(path);
}
}