diff --git a/EnvelopeGenerator.Application/Common/Dto/PdfSignOptionsDto.cs b/EnvelopeGenerator.Application/Common/Dto/PdfSignOptionsDto.cs
index 6ec8fa26..9b9ccf60 100644
--- a/EnvelopeGenerator.Application/Common/Dto/PdfSignOptionsDto.cs
+++ b/EnvelopeGenerator.Application/Common/Dto/PdfSignOptionsDto.cs
@@ -2,15 +2,53 @@ using EnvelopeGenerator.Application.Common.Enums;
namespace EnvelopeGenerator.Application.Common.Dto;
+///
+///
+///
public sealed record PdfSignOptionsDto
{
- public string? UUID { get; set; }
- public string? Name { get; set; }
- public string? Reason { get; set; }
- public string? Location { get; set; }
- public string? Email { get; set; }
- public string? Phone { get; set; }
- public string? ApplicationName { get; set; }
- public PdfSignatureCertificationLevel? CertificationLevel { get; set; }
- public PdfVisualSignatureOptionsDto? VisualSignature { get; set; }
+ ///
+ ///
+ ///
+ public string UUID { get; set; } = null!;
+
+ ///
+ ///
+ ///
+ public string Name { get; set; } = null!;
+
+ ///
+ ///
+ ///
+ public string Reason { get; set; } = null!;
+
+ ///
+ ///
+ ///
+ public string Location { get; set; } = null!;
+
+ ///
+ ///
+ ///
+ public string Email { get; set; } = null!;
+
+ ///
+ ///
+ ///
+ public string Phone { get; set; } = null!;
+
+ ///
+ ///
+ ///
+ public string ApplicationName { get; set; } = null!;
+
+ ///
+ ///
+ ///
+ public PdfSignatureCertificationLevel CertificationLevel { get; set; }
+
+ ///
+ ///
+ ///
+ public PdfVisualSignatureOptionsDto VisualSignature { get; set; } = null!;
}
diff --git a/EnvelopeGenerator.Application/Common/Dto/PdfVisualSignatureOptionsDto.cs b/EnvelopeGenerator.Application/Common/Dto/PdfVisualSignatureOptionsDto.cs
index 68591c13..4716c1bb 100644
--- a/EnvelopeGenerator.Application/Common/Dto/PdfVisualSignatureOptionsDto.cs
+++ b/EnvelopeGenerator.Application/Common/Dto/PdfVisualSignatureOptionsDto.cs
@@ -1,5 +1,15 @@
namespace EnvelopeGenerator.Application.Common.Dto;
+///
+///
+///
+///
+///
+///
+///
+///
+///
+///
public sealed record PdfVisualSignatureOptionsDto(
byte[] ImageBytes,
int PageNumber,
diff --git a/EnvelopeGenerator.Infrastructure.Crypt/Services/PdfDigitalSignatureService.cs b/EnvelopeGenerator.Infrastructure.Crypt/Services/PdfDigitalSignatureService.cs
index c3b97ad4..8aa933b0 100644
--- a/EnvelopeGenerator.Infrastructure.Crypt/Services/PdfDigitalSignatureService.cs
+++ b/EnvelopeGenerator.Infrastructure.Crypt/Services/PdfDigitalSignatureService.cs
@@ -18,10 +18,8 @@ public sealed class PdfDigitalSignatureService(IOptions options)
{
private static readonly Regex SignatureReasonMetaRegex = new(@"\|\s*SFMETA:v1;doc=(?[0-9a-fA-F-]{36});sha256=(?[A-Fa-f0-9]{64})$", RegexOptions.CultureInvariant | RegexOptions.Compiled);
- public async Task SignPdfAsync(Stream inputPdf, Stream outputPdf, PdfSignOptionsDto? optionsModel = null, CancellationToken cancellationToken = default)
+ public async Task SignPdfAsync(Stream inputPdf, Stream outputPdf, PdfSignOptionsDto request, CancellationToken cancellationToken = default)
{
- ArgumentNullException.ThrowIfNull(inputPdf);
- ArgumentNullException.ThrowIfNull(outputPdf);
cancellationToken.ThrowIfCancellationRequested();
var (workingInput, ownsWorkingInput) = await EnsureSeekableInputAsync(inputPdf, cancellationToken);
@@ -33,7 +31,7 @@ public sealed class PdfDigitalSignatureService(IOptions options)
workingInput.Position = 0;
var pkcs11Options = options.Value;
- var request = optionsModel ?? new PdfSignOptionsDto();
+
var uuid = ResolveUuid(request.UUID);
var reasonWithMeta = BuildReasonWithMeta(request.Reason ?? pkcs11Options.DefaultReason, uuid, sourceHashHex);
@@ -47,9 +45,9 @@ public sealed class PdfDigitalSignatureService(IOptions options)
Name = $"Sig_{DateTimeOffset.UtcNow:yyyyMMddHHmmss}"
};
- var signatureBounds = CreateSignatureBounds(request.VisualSignature);
- if (signatureBounds is not null)
- signatureFieldInfo.SignatureBounds = signatureBounds;
+ var left = request.VisualSignature!.Left;
+ var bottom = request.VisualSignature.Bottom;
+ signatureFieldInfo.SignatureBounds = new PdfRectangle(left, bottom, left + request.VisualSignature.Width, bottom + request.VisualSignature.Height);
var builder = new PdfDeferredSignatureBuilder(signerInfo, signatureFieldInfo)
{
@@ -64,21 +62,18 @@ public sealed class PdfDigitalSignatureService(IOptions options)
?? PdfCertificationLevel.NoCertification
};
- if(request.VisualSignature is PdfVisualSignatureOptionsDto visualSignature)
+ builder.SetSignatureAppearance(new PdfSignatureAppearance
{
- builder.SetSignatureAppearance(new PdfSignatureAppearance
- {
- AppearanceType = PdfSignatureAppearanceType.Name,
- ShowLabels = visualSignature.ShowLabels,
- ShowName = true,
- ShowDate = false,
- ShowReason = false,
- ShowLocation = false,
- ShowDistinguishedName = false
- });
- builder.SetImageData(visualSignature.ImageBytes);
- }
-
+ AppearanceType = PdfSignatureAppearanceType.Name,
+ ShowLabels = request.VisualSignature.ShowLabels,
+ ShowName = true,
+ ShowDate = false,
+ ShowReason = false,
+ ShowLocation = false,
+ ShowDistinguishedName = false
+ });
+ builder.SetImageData(request.VisualSignature.ImageBytes);
+
var deferredSigner = signer.SignDeferred(builder);
var externalSigner = new Pkcs11ExternalSigner(pkcs11Options);
deferredSigner.Sign(outputPdf, externalSigner.BuildSignature(deferredSigner.HashValue, digestCalculator.AlgorithmOid));
@@ -92,9 +87,6 @@ public sealed class PdfDigitalSignatureService(IOptions options)
public async Task SignPdfAsync(Stream inputPdf, Stream outputPdf, IReadOnlyList optionsList, CancellationToken cancellationToken = default)
{
- ArgumentNullException.ThrowIfNull(inputPdf);
- ArgumentNullException.ThrowIfNull(outputPdf);
- ArgumentNullException.ThrowIfNull(optionsList);
cancellationToken.ThrowIfCancellationRequested();
if (optionsList.Count == 0)
@@ -138,7 +130,6 @@ public sealed class PdfDigitalSignatureService(IOptions options)
public async Task CheckPdfSignatureAsync(Stream inputPdf, CancellationToken cancellationToken = default)
{
- ArgumentNullException.ThrowIfNull(inputPdf);
cancellationToken.ThrowIfCancellationRequested();
var pdfBytes = await ReadAllBytesAsync(inputPdf, cancellationToken);
@@ -246,8 +237,6 @@ public sealed class PdfDigitalSignatureService(IOptions options)
public async Task ExtractOriginalPdfAsync(Stream inputPdf, Stream outputPdf, CancellationToken cancellationToken = default)
{
- ArgumentNullException.ThrowIfNull(inputPdf);
- ArgumentNullException.ThrowIfNull(outputPdf);
cancellationToken.ThrowIfCancellationRequested();
var pdfBytes = await ReadAllBytesAsync(inputPdf, cancellationToken);
@@ -338,18 +327,25 @@ public sealed class PdfDigitalSignatureService(IOptions options)
KeyAlgorithm: certificate.PublicKey.Oid?.FriendlyName ?? certificate.PublicKey.Oid?.Value,
SignatureAlgorithm: certificate.SignatureAlgorithm.FriendlyName ?? certificate.SignatureAlgorithm.Value,
Pem: ToPem(certificate.RawData),
- KeySizeBits: TryGetKeySize(certificate));
+ KeySizeBits: TryGetKeySize(certificate, out var keySize) ? keySize : null);
}
- private static int? TryGetKeySize(X509Certificate2 certificate)
+ private static bool TryGetKeySize(X509Certificate2 certificate, out int keySize)
{
+ keySize = 0;
try
{
- return certificate.PublicKey.Key.KeySize;
+ using var rsa = certificate.GetRSAPublicKey();
+
+ if (rsa is null)
+ return false;
+
+ keySize = rsa.KeySize;
+ return true;
}
- catch
+ catch (CryptographicException)
{
- return null;
+ return false;
}
}
@@ -567,25 +563,6 @@ public sealed class PdfDigitalSignatureService(IOptions options)
return pageNumber;
}
- private static PdfRectangle? CreateSignatureBounds(PdfVisualSignatureOptionsDto? visualOptions)
- {
- if (visualOptions is null)
- return null;
-
- var left = visualOptions.Left;
- var bottom = visualOptions.Bottom;
- var width = visualOptions.Width;
- var height = visualOptions.Height;
-
- if (left < 0 || bottom < 0)
- throw new ArgumentOutOfRangeException(nameof(visualOptions), "VisualSignature.Left and VisualSignature.Bottom cannot be negative.");
-
- if (width <= 0 || height <= 0)
- throw new ArgumentOutOfRangeException(nameof(visualOptions), "VisualSignature.Width and VisualSignature.Height must be greater than zero.");
-
- return new PdfRectangle(left, bottom, left + width, bottom + height);
- }
-
private static string BuildReasonWithMeta(string? businessReason, string uuid, string sourceHashHex)
{
var trimmedReason = string.IsNullOrWhiteSpace(businessReason) ? null : businessReason.Trim();