diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/BouncySigner.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/BouncySigner.cs index 1aa06532..ee1cd90c 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/BouncySigner.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/BouncySigner.cs @@ -28,8 +28,10 @@ public BouncySigner(Tuple certific this.CertificateChain = certificateData.Item2; } - public byte[] GetSignedCms(Stream rangedStream, int pdfVersion) + public byte[] GetSignedCms(Stream rangedStream, int pdfVersion, byte[]? timestampToken = null) { + // TODO: Implement timestampToken usage, right now is being ignored + rangedStream.Position = 0; CmsSignedDataGenerator signedDataGenerator = new CmsSignedDataGenerator(); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/DefaultSigner.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/DefaultSigner.cs index cfcb7084..11ad750e 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/DefaultSigner.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/DefaultSigner.cs @@ -4,6 +4,7 @@ #if WPF using System.IO; #endif +using System.Security.Cryptography; using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; @@ -18,7 +19,7 @@ public DefaultSigner(X509Certificate2 Certificate) this.Certificate = Certificate; } - public byte[] GetSignedCms(Stream stream, int pdfVersion) + public byte[] GetSignedCms(Stream stream, int pdfVersion, byte[]? timestampToken = null) { var range = new byte[stream.Length]; @@ -26,11 +27,17 @@ public byte[] GetSignedCms(Stream stream, int pdfVersion) stream.Read(range, 0, range.Length); var contentInfo = new ContentInfo(range); - SignedCms signedCms = new SignedCms(contentInfo, true); CmsSigner signer = new CmsSigner(Certificate); + signer.UnsignedAttributes.Add(new Pkcs9SigningTime()); + if (timestampToken != null) + { + AsnEncodedData timestampTokenAsnEncodedData = new AsnEncodedData(new Oid("1.2.840.113549.1.9.16.2.14"), timestampToken); + signer.SignedAttributes.Add(new CryptographicAttributeObject(new Oid("1.2.840.113549.1.9.16.2.14"), new AsnEncodedDataCollection(timestampTokenAsnEncodedData))); + } + signedCms.ComputeSignature(signer, true); var bytes = signedCms.Encode(); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/ISigner.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/ISigner.cs index 8f5722c2..00c66d5a 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/ISigner.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/ISigner.cs @@ -9,7 +9,7 @@ namespace PdfSharp.Pdf.Signatures { public interface ISigner { - byte[] GetSignedCms(Stream stream, int pdfVersion); + byte[] GetSignedCms(Stream stream, int pdfVersion, byte[]? timestampToken = null); string GetName(); } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfSignatureHandler.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfSignatureHandler.cs index 59a202a5..e13079c2 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfSignatureHandler.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfSignatureHandler.cs @@ -21,6 +21,7 @@ public class PdfSignatureHandler { private PdfString signatureFieldContentsPdfString; private PdfArray signatureFieldByteRangePdfArray; + private byte[]? timestampToken; /// /// Cache signature length (bytes) for each PDF version since digest length depends on digest algorithm that depends on PDF version. @@ -52,19 +53,22 @@ public void AttachToDocument(PdfDocument documentToSign) // estimate signature length by computing signature for a fake byte[] if (!knownSignatureLengthInBytesByPdfVersion.ContainsKey(documentToSign.Version)) - knownSignatureLengthInBytesByPdfVersion[documentToSign.Version] = signer.GetSignedCms(new MemoryStream(new byte[] { 0 }), documentToSign.Version).Length; + knownSignatureLengthInBytesByPdfVersion[documentToSign.Version] = signer.GetSignedCms(new MemoryStream(new byte[] { 0 }), documentToSign.Version, timestampToken).Length; } - public PdfSignatureHandler(ISigner signer, PdfSignatureOptions options) + public PdfSignatureHandler(ISigner signer, PdfSignatureOptions options, byte[]? timestampToken = null) { - ArgumentNullException.ThrowIfNull(signer); - ArgumentNullException.ThrowIfNull(options); + if (signer is null) + throw new ArgumentNullException(nameof(signer)); + if (options is null) + throw new ArgumentNullException(nameof(options)); if (options.PageIndex < 0) throw new ArgumentOutOfRangeException($"Signature page index cannot be negative."); this.signer = signer; this.Options = options; + this.timestampToken = timestampToken; } private void ComputeSignatureAndRange(object sender, PdfDocumentEventArgs e) @@ -84,7 +88,7 @@ private void ComputeSignatureAndRange(object sender, PdfDocumentEventArgs e) // computing and writing document's digest - var signature = signer.GetSignedCms(rangedStreamToSign, Document.Version); + var signature = signer.GetSignedCms(rangedStreamToSign, Document.Version, timestampToken); if (signature.Length != knownSignatureLengthInBytesByPdfVersion[Document.Version]) throw new Exception("The digest length is different that the approximation made.");