签名后不允许更改的PDF设置



所以我遇到了一个有趣的问题。所以我知道在itext/itextsharp中,当你签名时,有一个关于PdfSignatureAppearance的设置,你可以设置CertificateLevel,这正如预期的那样,但最近我遇到了一个问题,我在签署一个文件时,该文件中的第一个签名是用PdfSignature Appearance.CERTIFIED_FORM_FILLING签名的,从而允许我使用(PdfSignatureAppearance.NOT_CERTIFIED)添加/签署签名,该签名用作批准签名。

所以我问这个问题的原因是我遇到了一个问题,我有一个文档,文档中有现有的签名字段,我用PdfSignatureAppearance.CERTIFIED_FORM_FILLING签署第一个签名,然后用PdfSignatureAppearance.NOT_CERTIFIED签署签名,但当我签署第二个签名字段时,第一个签名字段无效。

我使用的这个文档是使用FoxitPro创建的,但如果我在Adobe DC Pro中做同样的事情,它会像预期的那样工作。

如有任何建议,我们将不胜感激。

这是我用来签署pdf文档的代码,它只是signer类,所以其他对象和对该类的引用将丢失。

        public byte[] Sign(SignRequest request)
    {
        request.Document = SaveDocumentChanges(new SaveRequest
        {
            Document = request.Document,
            FormFields = request.FormFields,
            SigningBlocks = request.SigningBlocks
        }, request.Information);
        return SignDocument(request.Certificate, request.Information, request.SigningBlocks, request.SignatureImages, request.Document, request.IsFinalSignature);
    }
    private byte[] AddFormFields(List<FormField> formFields, byte[] document)
    {
        for (int i = 0; i < formFields.Count; i++)
        {
            using (MemoryStream outputStream = new MemoryStream())
            {
                using (PdfReader reader = new PdfReader(document))
                {
                    using (PdfStamper stamper = CreatePdfStamper(reader, outputStream, false))
                    {
                        if (!DoesFormFieldExist(reader, formFields[i].Name))
                        {
                            CreateFormField(reader, stamper, formFields[i]);
                        }
                        else
                        {
                            UpdateFormField(stamper, formFields[i]);
                        }
                    }
                }
                document = outputStream.ToArray();
            }
        }
        return document;
    }
    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 = CreatePdfStamper(reader, outputStream, false))
                    {
                        Dictionary<string, string> currentProperties = reader.Info;
                        foreach (string key in information.CustomProperties.Keys)
                        {
                            AddMetaDataAddDictionaryValue(currentProperties, key, information.CustomProperties[key]);
                        }
                        AddMetaDataAddDictionaryValue(currentProperties, "Producer", "Signisure");
                        AddMetaDataAddDictionaryValue(currentProperties, "Creator", "Signisure");
                        AddMetaDataAddDictionaryValue(currentProperties, "Author", "Signisure");
                        stamper.MoreInfo = currentProperties;
                    }
                }
                return outputStream.ToArray();
            }
        }
        return document;
    }
    private void AddMetaDataAddDictionaryValue(Dictionary<string, string> dictionary, string key, string value)
    {
        if (dictionary.ContainsKey(key))
        {
            dictionary[key] = value;
        }
        else
        {
            dictionary.Add(key, value);
        }
    }
    private void AddMetaDataAddDictionaryValue(PdfDictionary dictionary, PdfName key, PdfObject value)
    {
        if (!dictionary.Keys.Contains(key))
        {
            dictionary.Put(key, value);
        }
    }
    private byte[] AddSignatureFields(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 = CreatePdfStamper(reader, outputStream, false))
                    {
                        if (!DoesSignatureFieldExist(reader, signingBlocks[i].Name))
                        {
                            CreateSignatureField(stamper, signingBlocks[i]);
                        }
                    }
                }
                document = outputStream.ToArray();
            }
        }
        return document;
    }
    private void CreateFormField(PdfReader reader, PdfStamper stamper, FormField formField)
    {
        TextField field = new TextField(stamper.Writer, new Rectangle(formField.X, formField.Y, formField.X + formField.Width, formField.Y + formField.Height), formField.Name);
        field.Text = formField.Value;
        field.Font = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, BaseFont.EMBEDDED);
        field.FontSize = 12;
        field.Options = TextField.READ_ONLY;
        stamper.AddAnnotation(field.GetTextField(), formField.Page);
    }
    private PdfSignatureAppearance CreatePdfAppearance(PdfStamper stamper, SigningInformation information, string location, bool certify)
    {
        PdfSignatureAppearance appearance = stamper.SignatureAppearance;
        appearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
        CreatePdfAppearanceCertifyDocument(appearance, certify);
        if (information != null)
        {
            appearance.Location = location != String.Empty ? String.Format("{0} ({1})", location, information.IPAddress) : information.IPAddress;
            appearance.Reason = information.SignatoryReason;
            appearance.Contact = String.Format("{0} ({1})", information.Signatory, information.SignatoryEmail);
        }
        return appearance;
    }
    private void CreatePdfAppearanceCertifyDocument(PdfSignatureAppearance appearance, bool certify)
    {
        if (certify)
        {
            appearance.CertificationLevel = PdfSignatureAppearance.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS;
        }
        else
        {
            appearance.CertificationLevel = PdfSignatureAppearance.NOT_CERTIFIED;
        }
    }
    private PdfStamper CreatePdfStamper(PdfReader reader, MemoryStream outputStream, bool isSignature)
    {
        if (CreatePdfStamperIsPDFADocument(reader))
        {
            if (isSignature)
            {
                return PdfAStamper.CreateSignature(reader, outputStream, _pdfVersion, null, true, PdfAConformanceLevel.PDF_A_1A);
            }
            else
            {
                return new PdfAStamper(reader, outputStream, _pdfVersion, true, PdfAConformanceLevel.PDF_A_1A);
            }
        }
        else
        {
            if (isSignature)
            {
                return PdfStamper.CreateSignature(reader, outputStream, _pdfVersion, null, true);
            }
            else
            {
                return new PdfStamper(reader, outputStream, _pdfVersion, true);
            }
        }
    }
    private bool CreatePdfStamperIsPDFADocument(PdfReader reader)
    {
        if (reader.Metadata != null && reader.Metadata.Length > 0)
        {
            IXmpMeta xmpMeta = XmpMetaParser.Parse(reader.Metadata, null);
            IXmpProperty pdfaidConformance = xmpMeta.GetProperty(XmpConst.NS_PDFA_ID, "pdfaid:conformance");
            IXmpProperty pdfaidPart = xmpMeta.GetProperty(XmpConst.NS_PDFA_ID, "pdfaid:part");
            if (pdfaidConformance == null || pdfaidPart == null)
            {
                return false;
            }
            return true;
        }
        return false;
    }
    private void CreateSignatureField(PdfStamper stamper, SigningBlock signingBlock)
    {
        if (signingBlock == null)
        {
            return;
        }
        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;
        signatureField.Put(PdfName.CONTENTS, new PdfString(String.Empty));
        CreateSignatureFieldAddLockProperties(signatureField, signingBlock, stamper);
        stamper.AddAnnotation(signatureField, signingBlock.Page);
    }
    private void CreateSignatureFieldAddLockProperties(PdfFormField signatureField, SigningBlock signingBlock, PdfStamper stamper)
    {
        if (signingBlock.LinkedFormFields != null && signingBlock.LinkedFormFields.Count > 0)
        {
            PdfSigLockDictionary lockDictionary = new PdfSigLockDictionary(PdfSigLockDictionary.LockAction.INCLUDE, signingBlock.LinkedFormFields.ToArray());
            signatureField.Put(PdfName.LOCK, stamper.Writer.AddToBody(lockDictionary).IndirectReference);
        }
    }
    private bool DoesFormFieldExist(PdfReader reader, string formFieldName)
    {
        if (String.IsNullOrWhiteSpace(formFieldName))
        {
            return false;
        }
        return reader.AcroFields.Fields.Where(vp => vp.Key == formFieldName).Any();
    }
    private bool DoesSignatureFieldExist(PdfReader reader, string signatureFieldName)
    {
        if (String.IsNullOrWhiteSpace(signatureFieldName))
        {
            return false;
        }
        return reader.AcroFields.DoesSignatureFieldExist(signatureFieldName);
    }
    private AcroFields.FieldPosition GetAcroFieldByName(PdfStamper stamper, string signatureBlockName)
    {
        return stamper.AcroFields.GetFieldPositions(signatureBlockName).FirstOrDefault();
    }
    private List<string> GetAllSignatureFieldNames(PdfReader reader)
    {
        List<string> signatureFields = new List<string>();
        signatureFields.AddRange(reader.AcroFields.GetBlankSignatureNames());
        signatureFields.AddRange(reader.AcroFields.GetSignatureNames());
        return signatureFields;
    }
    private void GetDocumentFormFieldsBuildFormFields(List<FormField> formFields, PdfReader reader, PdfStamper stamper)
    {
        List<string> signatureFields = GetAllSignatureFieldNames(reader);
        foreach (KeyValuePair<string, AcroFields.Item> field in reader.AcroFields.Fields)
        {
            string fieldName = field.Key.ToString();
            if (!signatureFields.Where(signatureFieldName => signatureFieldName == fieldName).Any())
            {
                string fieldValue = reader.AcroFields.GetField(field.Key.ToString());
                AcroFields.FieldPosition formFieldPosition = GetAcroFieldByName(stamper, fieldName);
                formFields.Add(GetDocumentFormFieldsBuildFormFieldsCreateField(formFieldPosition, fieldName, fieldValue));
            }
        }
    }
    private FormField GetDocumentFormFieldsBuildFormFieldsCreateField(AcroFields.FieldPosition formFieldPosition, string fieldName, string fieldValue)
    {
        return new FormField
        {
            Height = (int)formFieldPosition.position.Height,
            Name = fieldName,
            Page = formFieldPosition.page,
            Width = (int)formFieldPosition.position.Width,
            X = (int)formFieldPosition.position.Left,
            Y = (int)formFieldPosition.position.Top,
            Value = fieldValue
        };
    }
    private void GetDocumentSignatureBlocksBuildSignatureBlocks(List<SigningBlock> signatureBlocks, List<string> signatureBlockNames, PdfReader reader, PdfStamper stamper, bool isSigned)
    {
        foreach (string signatureBlockName in signatureBlockNames)
        {
            AcroFields.FieldPosition signatureFieldPosition = GetAcroFieldByName(stamper, signatureBlockName);
            signatureBlocks.Add(GetDocumentSignatureBlocksBuildSignatureBlocksCreateBlock(signatureFieldPosition, signatureBlockName, isSigned));
        }
    }
    private SigningBlock GetDocumentSignatureBlocksBuildSignatureBlocksCreateBlock(AcroFields.FieldPosition signatureFieldPosition, string fieldName, bool isSigned)
    {
        return new SigningBlock
        {
            Height = (int)signatureFieldPosition.position.Height,
            Name = fieldName,
            Page = signatureFieldPosition.page,
            Width = (int)signatureFieldPosition.position.Width,
            X = (int)signatureFieldPosition.position.Left,
            Y = (int)signatureFieldPosition.position.Top,
            IsSigned = isSigned
        };
    }
    private string GetFormFieldValueForName(PdfStamper stamper, string formFieldName)
    {
        AcroFields formFields = stamper.AcroFields;
        return formFields.GetField(formFieldName);
    }
    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;
        }
        return null;
    }
    private byte[] SaveDocumentChanges(SaveRequest request, SigningInformation information)
    {
        request.Document = AddMetaData(information, request.Document);
        request.Document = AddFormFields(request.FormFields, request.Document);
        request.Document = AddSignatureFields(request.SigningBlocks, request.Document);
        return request.Document;
    }
    private byte[] SignDocument(Certificate certificate, SigningInformation information, List<SigningBlock> signingBlocks, List<MemberItemSignature> signatureImages, byte[] document, bool isFinalSignature)
    {
        for (int i = 0; i < signingBlocks.Count; i++)
        {
            document = SignDocumentSignSignatureField(certificate, information, signingBlocks[i], signatureImages, document, true);
        }
        if (isFinalSignature)
        {
            return SignDocumentLTVVerification(certificate, document);
        }
        return document;
    }
    private byte[] SignDocumentLTVVerification(Certificate certificate, byte[] document)
    {
        using (MemoryStream outputStream = new MemoryStream())
        {
            using (PdfReader reader = new PdfReader(document))
            {
                using (PdfStamper stamper = PdfStamper.CreateSignature(reader, outputStream, '', null, true))
                {
                    SignDocumentSigningBlockAddLTVVerification(stamper, certificate);
                }
            }
            return outputStream.ToArray();
        }
    }
    private void SignDocumentSigningBlock(SigningComponents components, SigningInformation information, SigningBlock block, PdfSignatureAppearance appearance, PdfStamper stamper, byte[] signatureImage)
    {
        appearance.SetVisibleSignature(block.Name);
        SignDocumentSigningBlockWithImage(signatureImage, appearance);
        SignDocumentSigningBlockWithText(appearance, information, appearance.SignDate);
        if (components.Certificate != null)
        {
            using (RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)components.Certificate.PrivateKey)
            {
                PrivateKeySignature privateKeySignature = SignDocumentSigningBlockBuildDigestSigningMethod(information, rsa) as PrivateKeySignature;
                SignatureHelper.Sign(appearance, privateKeySignature, components.CertificateChain, new List<ICrlClient> { components.CrlClient }, components.OcspClient, components.TimeStampingAuthority, Int32.Parse(_settingManager["DocumentSigningEstimatedDigestSize"]), CryptoStandard.CMS, SignDocumentSigningBlockCreateMetaData(information));
            }
        }
        else
        {
            HSMExternalSignature hsmExternalSignature = SignDocumentSigningBlockBuildDigestSigningMethod(information, null) as HSMExternalSignature;
            SignatureHelper.Sign(appearance, hsmExternalSignature, components.TimeStampingAuthority, Int32.Parse(_settingManager["DocumentSigningEstimatedDigestSize"]), CryptoStandard.CMS, SignDocumentSigningBlockCreateMetaData(information));
        }
    }
    private void SignDocumentSigningBlockAddLTVVerification(PdfStamper stamper, Certificate certificate)
    {
        SigningComponents components = new SigningComponents(_settingManager, certificate);
        LtvVerification ltvVerification = stamper.LtvVerification;
        List<string> signatureFieldNames = stamper.AcroFields.GetSignatureNames();
        PdfPKCS7 pkcs7 = stamper.AcroFields.VerifySignature(signatureFieldNames.Last());
        if (pkcs7.IsTsp)
        {
            bool validationAddedSuccessfully = ltvVerification.AddVerification(signatureFieldNames.Last(), components.OcspClient, components.CrlClient, LtvVerification.CertificateOption.SIGNING_CERTIFICATE, LtvVerification.Level.OCSP_CRL, LtvVerification.CertificateInclusion.YES);
        }
        else
        {
            foreach (string name in stamper.AcroFields.GetSignatureNames())
            {
                bool validationAddedSuccessfully = ltvVerification.AddVerification(name, components.OcspClient, components.CrlClient, LtvVerification.CertificateOption.WHOLE_CHAIN, LtvVerification.Level.OCSP_CRL, LtvVerification.CertificateInclusion.YES);
            }
        }
        ltvVerification.Merge();
        PdfSignatureAppearance appearance = stamper.SignatureAppearance;
        LtvTimestamp.Timestamp(appearance, components.TimeStampingAuthority, null);
    }
    private IExternalSignature SignDocumentSigningBlockBuildDigestSigningMethod(SigningInformation information, RSACryptoServiceProvider rsaCryptoProvider)
    {
        if (information.CertificateUse == CertificateUse.SignisureCertificate || rsaCryptoProvider == null)
        {
            return new HSMExternalSignature(_hsmService, _settingManager["DocumentSigningEncryptionHashAlgorithm"]);
        }
        else
        {
            return new PrivateKeySignature(DotNetUtilities.GetRsaKeyPair(rsaCryptoProvider).Private, _settingManager["DocumentSigningEncryptionHashAlgorithm"]);
        }
    }
    private PdfDictionary SignDocumentSigningBlockCreateMetaData(SigningInformation information)
    {
        PdfDictionary signatureDictionary = new PdfDictionary();
        if (!String.IsNullOrWhiteSpace(information.IdentificationInformation))
        {
            AddMetaDataAddDictionaryValue(signatureDictionary, new PdfName(".Signisure.IdentificationInformation"), new PdfString(information.IdentificationInformation));
        }
        if (!String.IsNullOrWhiteSpace(information.JuristicEntity))
        {
            AddMetaDataAddDictionaryValue(signatureDictionary, new PdfName(".Signisure.JuristicEntity"), new PdfString(information.JuristicEntity));
        }
        if (!String.IsNullOrWhiteSpace(information.Capacity))
        {
            AddMetaDataAddDictionaryValue(signatureDictionary, new PdfName(".Signisure.Capacity"), new PdfString(information.Capacity));
        }
        return signatureDictionary;
    }
    private void SignDocumentSigningBlockWithImage(byte[] signatureImage, PdfSignatureAppearance appearance)
    {
        if (signatureImage != null && signatureImage.Length > 0)
        {
            Image signatureImageInstance = Image.GetInstance(ImageHelper.FlattenImage(signatureImage));
            appearance.Image = signatureImageInstance;
            appearance.SignatureGraphic = signatureImageInstance;
        }
    }
    private void SignDocumentSigningBlockWithText(PdfSignatureAppearance appearance, SigningInformation information, DateTime timestampDateTime)
    {
        BaseFont verdana = BaseFont.CreateFont(AssemblyDirectory + "\Content\Fonts\Verdana\Verdana.ttf", BaseFont.CP1252, BaseFont.EMBEDDED);
        BaseFont helvetica = BaseFont.CreateFont(AssemblyDirectory + "\Content\Fonts\Helvetica\Helvetica.ttf", BaseFont.CP1252, BaseFont.EMBEDDED);
        BaseFont comicSans = BaseFont.CreateFont(AssemblyDirectory + "\Content\Fonts\ComicSans\ComicSans.ttf", BaseFont.CP1252, BaseFont.EMBEDDED);
        appearance.Layer2Text = SignDocumentSigningBlockWithTextBuildText(appearance, information, timestampDateTime);
        appearance.Layer2Font = new Font(verdana);
    }
    private string SignDocumentSigningBlockWithTextBuildText(PdfSignatureAppearance appearance, SigningInformation information, DateTime timestampDateTime)
    {
        return String.Format("Signee: {0}nSign date: {1}nLocation: {2}nReason: {3}", information.Signatory, timestampDateTime.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss zzz"), appearance.Location, appearance.Reason);
    }
    private byte[] SignDocumentSignSignatureField(Certificate certificate, SigningInformation information, SigningBlock signingBlock, List<MemberItemSignature> signatureImages, byte[] document, bool isVisible)
    {
        SigningComponents components = new SigningComponents(_settingManager, certificate);
        using (MemoryStream outputStream = new MemoryStream())
        {
            using (PdfReader reader = new PdfReader(document))
            {
                using (PdfStamper stamper = CreatePdfStamper(reader, outputStream, true))
                {
                    PdfSignatureAppearance appearance = CreatePdfAppearance(stamper, information, SignDocumentSignSignatureFieldBuildLocation(stamper, signingBlock), false);
                    SignDocumentSigningBlock(components, information, signingBlock, appearance, stamper, GetSignatureImage(signatureImages, signingBlock.Name));
                }
            }
            return outputStream.ToArray();
        }
    }
    private string SignDocumentSignSignatureFieldBuildLocation(PdfStamper stamper, SigningBlock signingBlock)
    {
        StringBuilder builder = new StringBuilder();
        for (int index = 0; index < signingBlock.LinkedFormFields.Count; index++)
        {
            builder.Append(GetFormFieldValueForName(stamper, signingBlock.LinkedFormFields[index]));
            if (index + 1 < signingBlock.LinkedFormFields.Count)
            {
                builder.Append(", ");
            }
        }
        return builder.ToString();
    }
    private void UpdateFormField(PdfStamper stamper, FormField formField)
    {
        AcroFields formFields = stamper.AcroFields;
        if (formField.Value != null && GetFormFieldValueForName(stamper, formField.Name) != formField.Value)
        {
            formFields.SetField(formField.Name, formField.Value);
            formFields.SetFieldProperty(formField.Name, "setfflags", PdfFormField.FF_READ_ONLY, null);
        }
    }
}

}

简短回答:

如果使用级别为PdfSignatureAppearance.CERTIFIED_FORM_FILLING的证书签名对文档进行签名,则可以添加任意数量的额外批准签名,而不会破坏原始(或先前)签名。

更长的答案:

如果你写:,没有人会相信你

我正在尝试首先使用PdfSignatureAppearance.CERTIFIED_FORM_FILLING对文档进行签名,这将允许我添加更多签名字段、编辑表单字段或对其他签名字段进行签名,但这会使我随后的签名无效。

你在这里说的不对。

然而,也许您没有正确签署PDF。请允许我重复我的简短回答:

如果使用级别为PdfSignatureAppearance.CERTIFIED_FORM_FILLING认证签名对文档进行签名,则可以添加任意数量的额外批准签名

我强调两个概念。PDF最多可以有一个证书签名(也称为作者签名),该签名应为文档中的第一个签名

。PDF可以有多个批准签名(也称为收件人签名)。

也许您正在使用证书签名对文档进行签名(我认为这是真的,因为您谈论的是证书级别)。也许您正在尝试添加第二个证书签名。显然,这会破坏PDF中的签名,因为PDF规范只允许一个证书签名。

也许您的问题是通过添加批准签名而不是证书签名来解决的。

最新更新