Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/271.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ITextSharp SetVisibleSignature未按预期工作_C#_Pdf_Itextsharp_Signing - Fatal编程技术网

C# ITextSharp SetVisibleSignature未按预期工作

C# ITextSharp SetVisibleSignature未按预期工作,c#,pdf,itextsharp,signing,C#,Pdf,Itextsharp,Signing,因此,我一直在使用IText的Java实现,但现在我正在编写一个签名过程到C#的端口,我遇到了一个障碍。因此,当我使用SetVisibleSignature(rect、page、name)重载对文档进行签名时,它会按预期对文档进行签名(只要签名字段不存在),但当我使用重载SetVisibleSignature(name)对现有字段进行签名时,它实际上不会对文档进行签名。我是在做一些愚蠢的事情,还是错过了什么 谢谢你的帮助 更新代码 using iTextSharp.text; using

因此,我一直在使用IText的Java实现,但现在我正在编写一个签名过程到C#的端口,我遇到了一个障碍。因此,当我使用SetVisibleSignature(rect、page、name)重载对文档进行签名时,它会按预期对文档进行签名(只要签名字段不存在),但当我使用重载SetVisibleSignature(name)对现有字段进行签名时,它实际上不会对文档进行签名。我是在做一些愚蠢的事情,还是错过了什么

谢谢你的帮助

更新代码

    using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using BouncyCastle = Org.BouncyCastle;

    public class DocumentSigner : IDocumentSigner
    {
        private const string _datetimeFormat = "dd/MM/yyyy hh:mm:ss";
        private readonly IDateTimeProvider _dateTimeProvider;
        private readonly ISettingManager _settingManager;

        public DocumentSigner(IDateTimeProvider dateTimeProvider, ISettingManager settingManager)
        {
            Guard.ArgumentNotNull(dateTimeProvider, "dateTimeProvider");
            Guard.ArgumentNotNull(settingManager, "settingManager");

            _dateTimeProvider = dateTimeProvider;
            _settingManager = settingManager;
        }

        public byte[] Sign(Certificate certificate, SigningInformation information, List<SigningBlock> signingBlocks, List<MemberItemSignature> signatureImages, byte[] document, bool certify)
        {
            document = AddMetaData(information, document);
            document = AddSignatureFields(information, signingBlocks, document);
            return SignDocument(certificate, information, signingBlocks, signatureImages, document, certify);
        }

        private byte[] AddMetaData(SigningInformation information, byte[] document)
        {
            if (information.CustomProperties != null && information.CustomProperties.Any())
            {
                using (MemoryStream outputStream = new MemoryStream())
                {
                    using (PdfReader reader = new PdfReader(document))
                    {
                        using (PdfStamper stamper = new PdfStamper(reader, outputStream, '\0', true))
                        {
                            Dictionary<string, string> currentProperties = reader.Info;
                            foreach (string key in information.CustomProperties.Keys)
                            {
                                if (currentProperties.ContainsKey(key))
                                {
                                    currentProperties[key] = information.CustomProperties[key];
                                }
                                else
                                {
                                    currentProperties.Add(key, information.CustomProperties[key]);
                                }
                            }

                            stamper.MoreInfo = currentProperties;
                        }
                    }

                    return outputStream.ToArray();
                }
            }

            return document;
        }

        private byte[] AddSignatureFields(SigningInformation information, List<SigningBlock> signingBlocks, byte[] document)
        {
            for (int i = 0; i < signingBlocks.Count; i++)
            {
                using (MemoryStream outputStream = new MemoryStream())
                {
                    using (PdfReader reader = new PdfReader(document))
                    {
                        using (PdfStamper stamper = new PdfStamper(reader, outputStream, '\0', true))
                        {
                            CreateSignatureField(reader, stamper, signingBlocks[i]);
                        }
                    }

                    document = outputStream.ToArray();
                }
            }

            return document;
        }

        private PdfSignatureAppearance CreatePdfAppearance(PdfStamper stamper, SigningInformation information, bool certify)
        {
            PdfSignatureAppearance appearance = stamper.SignatureAppearance;
            appearance.Location = information.Location;
            appearance.Reason = information.Purpose;
            appearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
            CreatePdfAppearanceCertifyDocument(appearance, certify);

            return appearance;
        }

        private void CreatePdfAppearanceCertifyDocument(PdfSignatureAppearance appearance, bool certify)
        {
            if (certify)
            {
                appearance.CertificationLevel = PdfSignatureAppearance.CERTIFIED_FORM_FILLING;
            }
            else
            {
                appearance.CertificationLevel = PdfSignatureAppearance.NOT_CERTIFIED;
            }
        }

        private PdfStamper CreatePdfStamper(PdfReader reader, MemoryStream outputStream, byte[] document)
        {
            return PdfStamper.CreateSignature(reader, outputStream, '\0', null, true);
        }

        private void CreateSignatureField(PdfReader reader, PdfStamper stamper, SigningBlock signingBlock)
        {
            if (signingBlock == null)
            {
                return;
            }

            if (!DoesSignatureFieldExist(reader, signingBlock.Name))
            {
                PdfFormField signatureField = PdfFormField.CreateSignature(stamper.Writer);
                signatureField.SetWidget(new Rectangle(signingBlock.X, signingBlock.Y, signingBlock.X + signingBlock.Width, signingBlock.Y + signingBlock.Height), null);
                signatureField.Flags = PdfAnnotation.FLAGS_PRINT;
                signatureField.FieldName = signingBlock.Name;
                signatureField.Page = signingBlock.Page;
                stamper.AddAnnotation(signatureField, signingBlock.Page);
            }
        }

        private bool DoesSignatureFieldExist(PdfReader reader, string signatureFieldName)
        {
            if (String.IsNullOrWhiteSpace(signatureFieldName))
            {
                return false;
            }

            return reader.AcroFields.DoesSignatureFieldExist(signatureFieldName);
        }

        private byte[] GetSignatureImage(List<MemberItemSignature> signatureImages, string signingBlockName)
        {
            MemberItemSignature signature = signingBlockName.Contains("Initial") ? signatureImages.Where(image => image.Use == SignatureUses.Initial).FirstOrDefault() : signatureImages.Where(image => image.Use == SignatureUses.Signature).FirstOrDefault();
            if (signature != null)
            {
                return signature.Image;
            }
            else
            {
                return null;
            }
        }

        private byte[] SignDocument(Certificate certificate, SigningInformation information, List<SigningBlock> signingBlocks, List<MemberItemSignature> signatureImages, byte[] document, bool certify)
        {
            for (int i = 0; i < signingBlocks.Count; i++)
            {
                using (MemoryStream outputStream = new MemoryStream())
                {
                    using (PdfReader reader = new PdfReader(document))
                    {
                        using (PdfStamper stamper = CreatePdfStamper(reader, outputStream, document))
                        {
                            SigningBlock signingBlock = signingBlocks[i];
                            PdfSignatureAppearance appearance = CreatePdfAppearance(stamper, information, certify && i == 0);

                            SignDocumentSigningBlock(certificate, information, signingBlock, appearance, stamper, GetSignatureImage(signatureImages, signingBlock.Name));
                        }
                    }

                    document = outputStream.ToArray();
                }
            }

            return document;
        }

        private void SignDocumentSigningBlock(Certificate certificate, SigningInformation information, SigningBlock block, PdfSignatureAppearance appearance, PdfStamper stamper, byte[] signatureImage)
        {
            X509Certificate2 x509Certificate = new X509Certificate2(certificate.Bytes, certificate.Password, X509KeyStorageFlags.Exportable);

            appearance.SetVisibleSignature(block.Name);
            SignDocumentSigningBlockWithImage(signatureImage, appearance);
            SignDocumentSigningBlockWithText(appearance, x509Certificate);

            using (RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)x509Certificate.PrivateKey)
            {
                IExternalSignature externalSignature = new PrivateKeySignature(DotNetUtilities.GetRsaKeyPair(rsa).Private, _settingManager["DocumentSigningEncryptionHashAlgorithm"]);
                MakeSignature.SignDetached(appearance, externalSignature, new BouncyCastle::X509.X509Certificate[] { DotNetUtilities.FromX509Certificate(x509Certificate) }, null, null, new TSAClientBouncyCastle(_settingManager["DocumentSigningTimestampingServiceAddress"]), Int32.Parse(_settingManager["DocumentSigningEstimatedTimestampSize"]), CryptoStandard.CMS);
            }
        }

        private void SignDocumentSigningBlockWithImage(byte[] signatureImage, PdfSignatureAppearance appearance)
        {
            if (signatureImage != null && signatureImage.Length > 0)
            {
                Image signatureImageInstance = Image.GetInstance(signatureImage);

                appearance.Image = signatureImageInstance;
                appearance.SignatureGraphic = signatureImageInstance;
            }
        }

        private void SignDocumentSigningBlockWithText(PdfSignatureAppearance appearance, X509Certificate2 x509Certificate)
        {
            if (x509Certificate == null)
            {
                return;
            }

            appearance.Layer2Text = SignDocumentSigningBlockWithTextBuildText(x509Certificate);
            appearance.Layer2Font = new Font(Font.FontFamily.COURIER, 7.0f, Font.NORMAL, BaseColor.LIGHT_GRAY);
            appearance.Acro6Layers = true;
        }

        private string SignDocumentSigningBlockWithTextBuildText(X509Certificate2 x509Certificate)
        {
            Dictionary<string, string> fields = SignDocumentSigningBlockWithTextBuildTextIssuerFields(x509Certificate.IssuerName.Name);

            string organization = fields.Keys.Contains("O") ? fields["O"] : String.Empty;
            string commonName = fields.Keys.Contains("CN") ? fields["CN"] : String.Empty;
            string signDate = _dateTimeProvider.Now.ToString(_datetimeFormat);
            string expirationDate = x509Certificate.NotAfter.ToString(_datetimeFormat);

            return "Digitally signed by " + organization + "\nSignee: " + commonName + "\nSign date: " + signDate + "\n" + "Expiration date: " + expirationDate;
        }

        private Dictionary<string, string> SignDocumentSigningBlockWithTextBuildTextIssuerFields(string issuer)
        {
            Dictionary<string, string> fields = new Dictionary<string, string>();

            string[] issuerFields = issuer.Split(',');
            foreach (string field in issuerFields)
            {
                string[] fieldSplit = field.Split('=');
                string key = fieldSplit[0].Trim();
                string value = fieldSplit[1].Trim();

                if (!fields.Keys.Contains(key))
                {
                    fields.Add(key, value);
                }
                else
                {
                    fields[key] = value;
                }
            }

            return fields;
        }
    }
OP提供的代码引用并访问未知类的多个对象。因此,为了使它能够运行,它必须被削减到自给自足的程度

幸运的是,精简版仍然可以用于重现和分析问题,参见后脚本。从这里开始的任何声明都基于此精简版本的行为

OP观察到的问题可以使用iTextSharp 5.5.7复制(并类似地使用iText 5.5.7),而且非常有趣的是,这两个库的版本5.5.6都无法复制。随着我对Java的深入,我研究了iText中的变化。他们以一种非常忠实的方式被移植到iTextSharp

事实上,这个问题是一个回归,在附加模式下对预先存在的空签名字段进行签名在iText(Sharp)5.5.7中被破坏

在5.5.6和5.5.7之间,
PdfSignatureAppearance.preClose
进行了更改。如果对现有签名字段进行签名,则用于操作相关签名字段的第一个小部件的代码(
af.getFieldItem(name).getWidget(0)
),现在它可以在关联的合并字典上工作(
af.getFieldItem(name).getMerged(0)

不幸的是,虽然前者是原始PDF中实际存在的对象,因此调用
writer.markUsed
,因为它标记了更改的内容以写入增量更新节,但后者与原始PDF中的对象不对应(它是多个对象的虚拟聚合),因此,调用
writer.markUsed
,因为它不再将要写入的更改标记为增量更新

因此,虽然实际签名值仍然写入文件,但它不再连接到指定的签名字段


已完成更改以修复方法行为

在此之前,
preClosed
工作不正确,因为它检索字段字典作为小部件注释。如果字段和小部件dict未合并,则该选项不正确。万一他们合并了,一切都如期进行。后者是数字签名字段最可能的情况,但根据规范它没有义务

(DEV-1448)

这是正确的,对于单独的字段和小部件字典,必须对字段而不是小部件进行某些更改。只是在append模式下,实现不能按预期工作


PS:这是OP代码的精简版本:

public class DocumentSigner
{
    private const string _datetimeFormat = "dd/MM/yyyy hh:mm:ss";

    public byte[] Sign(ICollection<X509Certificate> chain, ICipherParameters pk, string signingBlock, byte[] document, bool certify, String pattern = null)
    {
        document = AddMetaData(document);
        if (pattern != null)
            File.WriteAllBytes(String.Format(pattern, "1"), document);
        document = AddSignatureFields(signingBlock, document);
        if (pattern != null)
            File.WriteAllBytes(String.Format(pattern, "2"), document);
        return SignDocument(chain, pk, signingBlock, document, certify);
    }

    private byte[] AddMetaData(byte[] document)
    {
        return document;
    }

    private byte[] AddSignatureFields(string signingBlock, byte[] document)
    {
            using (MemoryStream outputStream = new MemoryStream())
            {
                using (PdfReader reader = new PdfReader(document))
                {
                    using (PdfStamper stamper = new PdfStamper(reader, outputStream, '\0', true))
                    {
                        CreateSignatureField(reader, stamper, signingBlock);
                    }
                }

                document = outputStream.ToArray();
            }

        return document;
    }

    private PdfSignatureAppearance CreatePdfAppearance(PdfStamper stamper, bool certify)
    {
        PdfSignatureAppearance appearance = stamper.SignatureAppearance;
        appearance.Location = "information.Location";
        appearance.Reason = "information.Purpose";
        appearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
        CreatePdfAppearanceCertifyDocument(appearance, certify);

        return appearance;
    }

    private void CreatePdfAppearanceCertifyDocument(PdfSignatureAppearance appearance, bool certify)
    {
        if (certify)
        {
            appearance.CertificationLevel = PdfSignatureAppearance.CERTIFIED_FORM_FILLING;
        }
        else
        {
            appearance.CertificationLevel = PdfSignatureAppearance.NOT_CERTIFIED;
        }
    }

    private PdfStamper CreatePdfStamper(PdfReader reader, MemoryStream outputStream, byte[] document)
    {
        return PdfStamper.CreateSignature(reader, outputStream, '\0', null, true);
    }

    private void CreateSignatureField(PdfReader reader, PdfStamper stamper, string signingBlock)
    {
        if (signingBlock == null)
        {
            return;
        }

        if (!DoesSignatureFieldExist(reader, signingBlock))
        {
            PdfFormField signatureField = PdfFormField.CreateSignature(stamper.Writer);
            signatureField.SetWidget(new Rectangle(100, 100, 200, 200), null);
            signatureField.Flags = PdfAnnotation.FLAGS_PRINT;
            signatureField.FieldName = signingBlock;
            signatureField.Page = 1;
            stamper.AddAnnotation(signatureField, 1);
        }
    }

    private bool DoesSignatureFieldExist(PdfReader reader, string signatureFieldName)
    {
        if (String.IsNullOrWhiteSpace(signatureFieldName))
        {
            return false;
        }

        return reader.AcroFields.DoesSignatureFieldExist(signatureFieldName);
    }

    private byte[] GetSignatureImage(string signingBlockName)
    {
        return null;
    }

    private byte[] SignDocument(ICollection<X509Certificate> chain, ICipherParameters pk, string signingBlock, byte[] document, bool certify)
    {
            using (MemoryStream outputStream = new MemoryStream())
            {
                using (PdfReader reader = new PdfReader(document))
                {
                    using (PdfStamper stamper = CreatePdfStamper(reader, outputStream, document))
                    {
                        PdfSignatureAppearance appearance = CreatePdfAppearance(stamper, certify);

                        SignDocumentSigningBlock(chain, pk, signingBlock, appearance, stamper, GetSignatureImage(signingBlock));
                    }
                }

                document = outputStream.ToArray();
            }

        return document;
    }

    private void SignDocumentSigningBlock(ICollection<X509Certificate> chain, ICipherParameters pk, string block, PdfSignatureAppearance appearance, PdfStamper stamper, byte[] signatureImage)
    {
        appearance.SetVisibleSignature(block);
        SignDocumentSigningBlockWithImage(signatureImage, appearance);
        SignDocumentSigningBlockWithText(appearance, chain.First());

        IExternalSignature externalSignature = new PrivateKeySignature(pk, "SHA-256");
        MakeSignature.SignDetached(appearance, externalSignature, chain, null, null, new TSAClientBouncyCastle("http://services.globaltrustfinder.com/adss/tsa"), 104000, CryptoStandard.CMS);
    }

    private void SignDocumentSigningBlockWithImage(byte[] signatureImage, PdfSignatureAppearance appearance)
    {
        if (signatureImage != null && signatureImage.Length > 0)
        {
            Image signatureImageInstance = Image.GetInstance(signatureImage);

            appearance.Image = signatureImageInstance;
            appearance.SignatureGraphic = signatureImageInstance;
        }
    }

    private void SignDocumentSigningBlockWithText(PdfSignatureAppearance appearance, X509Certificate x509Certificate)
    {
        if (x509Certificate == null)
        {
            return;
        }

        appearance.Layer2Text = SignDocumentSigningBlockWithTextBuildText(x509Certificate);
        appearance.Layer2Font = new Font(Font.FontFamily.COURIER, 7.0f, Font.NORMAL, BaseColor.LIGHT_GRAY);
        appearance.Acro6Layers = true;
    }

    private string SignDocumentSigningBlockWithTextBuildText(X509Certificate x509Certificate)
    {
        Dictionary<string, string> fields = SignDocumentSigningBlockWithTextBuildTextIssuerFields(x509Certificate.IssuerDN.ToString());

        string organization = fields.Keys.Contains("O") ? fields["O"] : String.Empty;
        string commonName = fields.Keys.Contains("CN") ? fields["CN"] : String.Empty;
        string signDate = System.DateTime.Now.ToString(_datetimeFormat);
        string expirationDate = x509Certificate.NotAfter.ToString();

        return "Digitally signed by " + organization + "\nSignee: " + commonName + "\nSign date: " + signDate + "\n" + "Expiration date: " + expirationDate;
    }

    private Dictionary<string, string> SignDocumentSigningBlockWithTextBuildTextIssuerFields(string issuer)
    {
        Dictionary<string, string> fields = new Dictionary<string, string>();

        string[] issuerFields = issuer.Split(',');
        foreach (string field in issuerFields)
        {
            string[] fieldSplit = field.Split('=');
            string key = fieldSplit[0].Trim();
            string value = fieldSplit[1].Trim();

            if (!fields.Keys.Contains(key))
            {
                fields.Add(key, value);
            }
            else
            {
                fields[key] = value;
            }
        }

        return fields;
    }
}
公共类文档签名器
{
私有常量字符串_datetimeFormat=“dd/MM/yyyy hh:MM:ss”;
公共字节[]符号(ICollection链,ICipherParameters pk,字符串签名块,字节[]文档,bool certifite,字符串模式=null)
{
文档=添加元数据(文档);
if(模式!=null)
File.writealBytes(String.Format(模式,“1”),文档);
文件=添加签名字段(签名块、文件);
if(模式!=null)
File.writealBytes(String.Format(模式,“2”),文档);
返回签名文件(链、主键、签名块、文件、证明);
}
专用字节[]添加元数据(字节[]文档)
{
归还文件;
}
专用字节[]AddSignatureFields(字符串签名块,字节[]文档)
{
使用(MemoryStream outputStream=new MemoryStream())
{
使用(PDF阅读器=新PDF阅读器(文档))
{
使用(PdfStamper压模=新的PdfStamper(读卡器,输出流,'\0',真))
{
CreateSignatureField(读卡器、压模、签名块);
}
}
document=outputStream.ToArray();
}
归还文件;
}
私人PDFSignaturePearance CreatePDFaAppearance(PdfStamper压模,bool认证)
{
PDFSignaturePearance外观=母版。SignaturePearance;
外观.Location=“信息.Location”;
外观.Reason=“信息.目的”;
外观.SignatureRenderingMode=PdfSignatureAppearance.RenderingMode.DESCRIPTION;
CreatePDFaAppearanceCertifyDocument(外观、认证);
返回外观;
}
私有无效CreatePDFaAppearanceCertifyDocument(PdfSignatureAppearance外观,bool certify)
{
如果(证明)
{
外观.CertificationLevel=PdfSignatureAppearance.CERTIFIED\u表格\u填写;
}
其他的
{
appearance.CertificationLevel=PdfSignatureAppearance.NOT_CERTIFIED;
}
}
专用PdfStamper CreatePdfStamper(PdfReader读取器、MemoryStream outputStream、byte[]文档)
{
返回PdfStamper.CreateSignature(读取器,outputStream,'\0',null,true);
}
私有void CreateSignatureField(PDF读卡器、PdfStamper压模、字符串签名块)
{
if(signingBlock==null)
{
返回;
}
如果(!DoesSignatureFieldExist(读卡器、签名块))
{
PdfFormField signatureField=PdfFormField.CreateSignature(stamper.Writer);
SetWidget(新矩形(100100200200),null);
signatureField.Flags=PdfAnnotation.Flags\u打印;
签名纸
public class DocumentSigner
{
    private const string _datetimeFormat = "dd/MM/yyyy hh:mm:ss";

    public byte[] Sign(ICollection<X509Certificate> chain, ICipherParameters pk, string signingBlock, byte[] document, bool certify, String pattern = null)
    {
        document = AddMetaData(document);
        if (pattern != null)
            File.WriteAllBytes(String.Format(pattern, "1"), document);
        document = AddSignatureFields(signingBlock, document);
        if (pattern != null)
            File.WriteAllBytes(String.Format(pattern, "2"), document);
        return SignDocument(chain, pk, signingBlock, document, certify);
    }

    private byte[] AddMetaData(byte[] document)
    {
        return document;
    }

    private byte[] AddSignatureFields(string signingBlock, byte[] document)
    {
            using (MemoryStream outputStream = new MemoryStream())
            {
                using (PdfReader reader = new PdfReader(document))
                {
                    using (PdfStamper stamper = new PdfStamper(reader, outputStream, '\0', true))
                    {
                        CreateSignatureField(reader, stamper, signingBlock);
                    }
                }

                document = outputStream.ToArray();
            }

        return document;
    }

    private PdfSignatureAppearance CreatePdfAppearance(PdfStamper stamper, bool certify)
    {
        PdfSignatureAppearance appearance = stamper.SignatureAppearance;
        appearance.Location = "information.Location";
        appearance.Reason = "information.Purpose";
        appearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
        CreatePdfAppearanceCertifyDocument(appearance, certify);

        return appearance;
    }

    private void CreatePdfAppearanceCertifyDocument(PdfSignatureAppearance appearance, bool certify)
    {
        if (certify)
        {
            appearance.CertificationLevel = PdfSignatureAppearance.CERTIFIED_FORM_FILLING;
        }
        else
        {
            appearance.CertificationLevel = PdfSignatureAppearance.NOT_CERTIFIED;
        }
    }

    private PdfStamper CreatePdfStamper(PdfReader reader, MemoryStream outputStream, byte[] document)
    {
        return PdfStamper.CreateSignature(reader, outputStream, '\0', null, true);
    }

    private void CreateSignatureField(PdfReader reader, PdfStamper stamper, string signingBlock)
    {
        if (signingBlock == null)
        {
            return;
        }

        if (!DoesSignatureFieldExist(reader, signingBlock))
        {
            PdfFormField signatureField = PdfFormField.CreateSignature(stamper.Writer);
            signatureField.SetWidget(new Rectangle(100, 100, 200, 200), null);
            signatureField.Flags = PdfAnnotation.FLAGS_PRINT;
            signatureField.FieldName = signingBlock;
            signatureField.Page = 1;
            stamper.AddAnnotation(signatureField, 1);
        }
    }

    private bool DoesSignatureFieldExist(PdfReader reader, string signatureFieldName)
    {
        if (String.IsNullOrWhiteSpace(signatureFieldName))
        {
            return false;
        }

        return reader.AcroFields.DoesSignatureFieldExist(signatureFieldName);
    }

    private byte[] GetSignatureImage(string signingBlockName)
    {
        return null;
    }

    private byte[] SignDocument(ICollection<X509Certificate> chain, ICipherParameters pk, string signingBlock, byte[] document, bool certify)
    {
            using (MemoryStream outputStream = new MemoryStream())
            {
                using (PdfReader reader = new PdfReader(document))
                {
                    using (PdfStamper stamper = CreatePdfStamper(reader, outputStream, document))
                    {
                        PdfSignatureAppearance appearance = CreatePdfAppearance(stamper, certify);

                        SignDocumentSigningBlock(chain, pk, signingBlock, appearance, stamper, GetSignatureImage(signingBlock));
                    }
                }

                document = outputStream.ToArray();
            }

        return document;
    }

    private void SignDocumentSigningBlock(ICollection<X509Certificate> chain, ICipherParameters pk, string block, PdfSignatureAppearance appearance, PdfStamper stamper, byte[] signatureImage)
    {
        appearance.SetVisibleSignature(block);
        SignDocumentSigningBlockWithImage(signatureImage, appearance);
        SignDocumentSigningBlockWithText(appearance, chain.First());

        IExternalSignature externalSignature = new PrivateKeySignature(pk, "SHA-256");
        MakeSignature.SignDetached(appearance, externalSignature, chain, null, null, new TSAClientBouncyCastle("http://services.globaltrustfinder.com/adss/tsa"), 104000, CryptoStandard.CMS);
    }

    private void SignDocumentSigningBlockWithImage(byte[] signatureImage, PdfSignatureAppearance appearance)
    {
        if (signatureImage != null && signatureImage.Length > 0)
        {
            Image signatureImageInstance = Image.GetInstance(signatureImage);

            appearance.Image = signatureImageInstance;
            appearance.SignatureGraphic = signatureImageInstance;
        }
    }

    private void SignDocumentSigningBlockWithText(PdfSignatureAppearance appearance, X509Certificate x509Certificate)
    {
        if (x509Certificate == null)
        {
            return;
        }

        appearance.Layer2Text = SignDocumentSigningBlockWithTextBuildText(x509Certificate);
        appearance.Layer2Font = new Font(Font.FontFamily.COURIER, 7.0f, Font.NORMAL, BaseColor.LIGHT_GRAY);
        appearance.Acro6Layers = true;
    }

    private string SignDocumentSigningBlockWithTextBuildText(X509Certificate x509Certificate)
    {
        Dictionary<string, string> fields = SignDocumentSigningBlockWithTextBuildTextIssuerFields(x509Certificate.IssuerDN.ToString());

        string organization = fields.Keys.Contains("O") ? fields["O"] : String.Empty;
        string commonName = fields.Keys.Contains("CN") ? fields["CN"] : String.Empty;
        string signDate = System.DateTime.Now.ToString(_datetimeFormat);
        string expirationDate = x509Certificate.NotAfter.ToString();

        return "Digitally signed by " + organization + "\nSignee: " + commonName + "\nSign date: " + signDate + "\n" + "Expiration date: " + expirationDate;
    }

    private Dictionary<string, string> SignDocumentSigningBlockWithTextBuildTextIssuerFields(string issuer)
    {
        Dictionary<string, string> fields = new Dictionary<string, string>();

        string[] issuerFields = issuer.Split(',');
        foreach (string field in issuerFields)
        {
            string[] fieldSplit = field.Split('=');
            string key = fieldSplit[0].Trim();
            string value = fieldSplit[1].Trim();

            if (!fields.Keys.Contains(key))
            {
                fields.Add(key, value);
            }
            else
            {
                fields[key] = value;
            }
        }

        return fields;
    }
}