using DevExpress.Pdf; using DevExpress.Office.DigitalSignatures; namespace DXApp.TemplateKitProject.Services; /// /// Service zum digitalen Signieren von PDF-Dokumenten mit DevExpress PdfDocumentSigner /// public class PdfSigningService( IConfiguration configuration, ILogger logger) { /// /// Signiert eine PDF-Datei mit einem PFX-Zertifikat /// public async Task SignPdfAsync(byte[] pdfBytes, PdfSigningOptions? options = null) { options ??= new PdfSigningOptions(); return await Task.Run(() => { try { // Zertifikat-Konfiguration laden var certPath = options.CertificatePath ?? configuration["PdfSigning:CertificatePath"] ?? throw new InvalidOperationException("PdfSigning:CertificatePath nicht konfiguriert."); var certPassword = options.CertificatePassword ?? configuration["PdfSigning:CertificatePassword"] ?? throw new InvalidOperationException("PdfSigning:CertificatePassword nicht konfiguriert."); logger.LogInformation("PDF wird signiert mit Zertifikat: {Path}", certPath); // PDF in MemoryStream laden using var inputStream = new MemoryStream(pdfBytes); using var signer = new PdfDocumentSigner(inputStream); // PKCS#7 Signatur erstellen var pkcs7Signature = new Pkcs7Signer(certPath, certPassword, HashAlgorithmType.SHA256); // Signatur-Feld definieren var fieldInfo = new PdfSignatureFieldInfo(signer.PageCount - 1); // Letzte Seite fieldInfo.Name = $"Signature_{DateTime.Now:yyyyMMdd_HHmmss}"; fieldInfo.SignatureBounds = new PdfRectangle( options.SignatureX, options.SignatureY, options.SignatureX + options.SignatureWidth, options.SignatureY + options.SignatureHeight ); // Signatur-Builder erstellen var signatureBuilder = new PdfSignatureBuilder(pkcs7Signature, fieldInfo); signatureBuilder.Name = options.SignerName; signatureBuilder.Location = options.Location; signatureBuilder.Reason = options.Reason; // Optional: Signatur-Bild hinzufügen if (!string.IsNullOrEmpty(options.SignatureImagePath) && File.Exists(options.SignatureImagePath)) { signatureBuilder.SetImageData(File.ReadAllBytes(options.SignatureImagePath)); logger.LogDebug("Signatur-Bild hinzugefügt: {Path}", options.SignatureImagePath); } // Signierte PDF in MemoryStream speichern using var outputStream = new MemoryStream(); signer.SaveDocument(outputStream, signatureBuilder); logger.LogInformation( "PDF erfolgreich signiert. Größe: {Original} KB ? {Signed} KB", pdfBytes.Length / 1024, outputStream.Length / 1024 ); return outputStream.ToArray(); } catch (Exception ex) { logger.LogError(ex, "Fehler beim Signieren der PDF-Datei."); throw; } }); } /// /// Liest Signatur-Informationen aus einer signierten PDF /// public async Task> GetSignatureInfoAsync(byte[] pdfBytes) { return await Task.Run(() => { try { using var stream = new MemoryStream(pdfBytes); using var signer = new PdfDocumentSigner(stream); var signatures = signer.GetSignatureInfo(); var result = new List(); foreach (var sig in signatures) { var info = new SignatureInformation { FieldName = sig.FieldName, SignerName = sig.SignerName, Location = sig.Location, Reason = sig.Reason, Date = DateTime.Now, // Wird später aus PKCS#7 gelesen CertificationLevel = sig.CertificationLevel.ToString() }; // PKCS#7 Details auslesen try { var pkcs7 = signer.GetPdfPkcs7Signature(sig.FieldName); var cert = pkcs7.GetSignatureCertificate(); // Signatur-Datum: GetTimeStampDate oder aktuelles Datum var timestampDate = pkcs7.GetTimeStampDate(); info.Date = timestampDate ?? DateTime.Now; info.IsSignatureValid = pkcs7.VerifySignature(); info.IsCertificateValid = cert.Verify(); info.CertificateIssuer = cert.IssuerName.Name ?? string.Empty; info.CertificateSubject = cert.SubjectName.Name ?? string.Empty; info.CertificateValidUntil = cert.NotAfter; } catch (Exception ex) { logger.LogWarning(ex, "Fehler beim Auslesen der PKCS#7-Details für Signatur '{Name}'", sig.FieldName); } result.Add(info); } logger.LogInformation("PDF enthält {Count} Signatur(en)", result.Count); return result; } catch (Exception ex) { logger.LogError(ex, "Fehler beim Auslesen der Signatur-Informationen."); throw; } }); } } /// /// Optionen für die PDF-Signatur /// public class PdfSigningOptions { public string? CertificatePath { get; set; } public string? CertificatePassword { get; set; } public string SignerName { get; set; } = "DXApp System"; public string Location { get; set; } = "Digital Data AG"; public string Reason { get; set; } = "Dokument digital signiert"; // Position und Größe der sichtbaren Signatur (in Points, 72 DPI) public double SignatureX { get; set; } = 50; public double SignatureY { get; set; } = 50; public double SignatureWidth { get; set; } = 200; public double SignatureHeight { get; set; } = 80; public string? SignatureImagePath { get; set; } } /// /// Informationen über eine PDF-Signatur /// public class SignatureInformation { public string FieldName { get; set; } = string.Empty; public string SignerName { get; set; } = string.Empty; public string Location { get; set; } = string.Empty; public string Reason { get; set; } = string.Empty; public DateTime Date { get; set; } public string CertificationLevel { get; set; } = string.Empty; public bool IsSignatureValid { get; set; } public bool IsCertificateValid { get; set; } public string CertificateIssuer { get; set; } = string.Empty; public string CertificateSubject { get; set; } = string.Empty; public DateTime CertificateValidUntil { get; set; } }