using EnvelopeGenerator.Application.Common.Configurations; using DevExpress.Office.DigitalSignatures; using DevExpress.Pdf; namespace EnvelopeGenerator.Infrastructure.Crypt.Services; internal sealed class Pkcs11ExternalSigner(Pkcs11Options options) : Pkcs7SignerBase { private readonly Pkcs11PdfSigningRsa rsa = new(options); private readonly DigestCalculator digestCalculator = new(HashAlgorithmType.SHA256); private readonly IReadOnlyList certificates = [ReadCertificateBytesWithFallback(options)]; protected override IDigestCalculator DigestCalculator => digestCalculator; protected override string SigningAlgorithmOID => "1.2.840.113549.1.1.1"; protected override IEnumerable GetCertificates() => certificates; protected override byte[] SignDigest(byte[] digest) { return rsa.SignHash(digest, System.Security.Cryptography.HashAlgorithmName.SHA256, System.Security.Cryptography.RSASignaturePadding.Pkcs1); } private static byte[] ReadCertificateBytesWithFallback(Pkcs11Options options) { try { return Pkcs11SessionRunner.Run(options, session => { var attrs = new List { session.Factories.ObjectAttributeFactory.Create(Net.Pkcs11Interop.Common.CKA.CKA_CLASS, Net.Pkcs11Interop.Common.CKO.CKO_CERTIFICATE), session.Factories.ObjectAttributeFactory.Create(Net.Pkcs11Interop.Common.CKA.CKA_LABEL, options.CertificateLabel) }; var handles = session.FindAllObjects(attrs); if (handles.Count == 0) throw new InvalidOperationException($"Certificate '{options.CertificateLabel}' not found in token."); var values = session.GetAttributeValue(handles[0], new List { Net.Pkcs11Interop.Common.CKA.CKA_VALUE }); return values[0].GetValueAsByteArray(); }); } catch when (Pkcs11ToolBridge.IsAvailable(options)) { return Pkcs11ToolBridge.ReadCertificateBytes(options); } } }