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,64 @@
|
||||
using EnvelopeGenerator.Application.Common.Configurations;
|
||||
using Net.Pkcs11Interop.Common;
|
||||
using Net.Pkcs11Interop.HighLevelAPI;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace EnvelopeGenerator.Infrastructure.Crypt.Services;
|
||||
|
||||
internal sealed class Pkcs11PdfSigningRsa(Pkcs11Options options) : RSA
|
||||
{
|
||||
public override int KeySize
|
||||
{
|
||||
get => KeySizeValue;
|
||||
set => KeySizeValue = value;
|
||||
}
|
||||
|
||||
public override KeySizes[] LegalKeySizes => [new(1024, 8192, 8)];
|
||||
public override string? KeyExchangeAlgorithm => "RSA";
|
||||
public override string SignatureAlgorithm => "RSA";
|
||||
|
||||
public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
|
||||
{
|
||||
if (padding != RSASignaturePadding.Pkcs1)
|
||||
throw new NotSupportedException("Only RSA PKCS#1 v1.5 padding is supported.");
|
||||
|
||||
byte[] digestInfo = Pkcs11DigestInfoBuilder.Build(hash, hashAlgorithm);
|
||||
try
|
||||
{
|
||||
return Pkcs11SessionRunner.Run(options, session =>
|
||||
{
|
||||
var attrs = new List<IObjectAttribute>
|
||||
{
|
||||
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
|
||||
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_LABEL, options.PrivateKeyLabel)
|
||||
};
|
||||
|
||||
var handles = session.FindAllObjects(attrs);
|
||||
if (handles.Count == 0)
|
||||
throw new InvalidOperationException($"Private key '{options.PrivateKeyLabel}' not found in token.");
|
||||
|
||||
var mechanism = session.Factories.MechanismFactory.Create(CKM.CKM_RSA_PKCS);
|
||||
return session.Sign(mechanism, handles[0], digestInfo);
|
||||
});
|
||||
}
|
||||
catch when (Pkcs11ToolBridge.IsAvailable(options))
|
||||
{
|
||||
return Pkcs11ToolBridge.SignDigestInfo(options, digestInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool VerifyHash(byte[] hash, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override byte[] Encrypt(byte[] data, RSAEncryptionPadding padding)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override RSAParameters ExportParameters(bool includePrivateParameters)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override void ImportParameters(RSAParameters parameters)
|
||||
=> throw new NotSupportedException();
|
||||
}
|
||||
Reference in New Issue
Block a user