Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ public BouncySigner(Tuple<X509Certificate2, X509Certificate2Collection> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#if WPF
using System.IO;
#endif
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;

Expand All @@ -18,19 +19,25 @@ 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];

stream.Position = 0;
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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class PdfSignatureHandler
{
private PdfString signatureFieldContentsPdfString;
private PdfArray signatureFieldByteRangePdfArray;
private byte[]? timestampToken;

/// <summary>
/// Cache signature length (bytes) for each PDF version since digest length depends on digest algorithm that depends on PDF version.
Expand Down Expand Up @@ -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)
Expand All @@ -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.");
Expand Down