itext

iText8 Signature without reason or location


I am trying to create a signature in a pdf document without the reason and location on it.

StampingProperties properties = new StampingProperties();
properties.UseAppendMode();                               

string fieldName = $"signature_{obj.Signer.Replace(" ", "_")}_{count}";
var IMG = "sig.jpg";

SignerProperties signerProperties = new SignerProperties();
signerProperties.SetPageRect(rectangle);
signerProperties.SetPageNumber(pageNr);
signerProperties.SetFieldName(fieldName);
signerProperties.SetSignatureCreator(signer);
signerProperties.SetSignDate(signDate);
signerProperties.SetReason("");
signerProperties.SetLocation("");

var signatureAppearance = new SignatureFieldAppearance(fieldName);                                                                
signatureAppearance.SetContent(new SignedAppearanceText().SetReasonLine("").SetLocationLine(""));
signatureAppearance.SetBackgroundImage(
    new BackgroundImage.Builder()
        .SetImage(new PdfImageXObject(ImageDataFactory.Create(IMG)))                                             
        .Build());
signerProperties.SetSignatureAppearance(signatureAppearance);

PdfSigner signer = new PdfSigner(pdfReader, outputStream, null, properties, signerProperties);
signer.SignDetached(eidSignature, chain, crlList, null, tsaClient, 0, PdfSigner.CryptoStandard.CADES);

I have tried to set the reason and location to an empty string in the SignatureFieldAppearance and the SignerProperties, but this does not work. What do I need to change in order for this to work?


Solution

  • Indeed, it used to be possible to use empty or null strings for reason and location to make iText drop the associated line in the signature appearance. That this does not work in an obvious manner is a regression which has already been fixed now in the development sources, see this commit.

    If you need an official iText release and cannot compile your own from the current sources, there is a work-around (proposed by iText development): You can create a custom signed appearance text class that accepts a specific non-null, non-empty signal string to drop the reason and/or location like this:

    class CustomSignedAppearanceText : SignedAppearanceText
    {
        public override string GenerateDescriptionText()
        {
            StringBuilder stringBuilder = new StringBuilder();
            string signedBy = GetSignedBy();
            if (signedBy != null && !string.IsNullOrEmpty(signedBy))
            {
                stringBuilder.Append("Digitally signed by ").Append(signedBy);
            }
    
            if (isSignDateSet)
            {
                stringBuilder.Append('\n').Append("Date: ").Append(DateTimeUtil.DateToString(GetSignDate()));
            }
            string reason = GetReasonLine();
            if (reason != null && !string.IsNullOrEmpty(reason) && !"DROP".Equals(reason))
            {
                stringBuilder.Append('\n').Append(reason);
            }
            string location = GetLocationLine();
            if (location != null && !string.IsNullOrEmpty(location) && !"DROP".Equals(location))
            {
                stringBuilder.Append('\n').Append(location);
            }
    
            return stringBuilder.ToString();
        }
    
        public override SignedAppearanceText SetSignDate(DateTime signDate)
        {
            isSignDateSet = true;
            return base.SetSignDate(signDate);
        }
    
        bool isSignDateSet = false;
    }
    

    (SignWithoutReasonOrLocation helper class)

    With that you can use "DROP" to signal that you want to have the line in question dropped:

    signatureAppearance.SetContent(new CustomSignedAppearanceText().SetReasonLine("DROP").SetLocationLine("DROP"));
    

    (SignWithoutReasonOrLocation test SignLikeTaniaVanderstraetenWorkAround)