Skip to content

Commit 74c3b15

Browse files
Do not mark annotations as modified when simply reading them in append mode
Also avoid possible NPE in case of invalid PDFs in which page annotations array contains invalid indirect reference. DEVSIX-2830
1 parent e9ebcc0 commit 74c3b15

File tree

4 files changed

+73
-4
lines changed

4 files changed

+73
-4
lines changed

kernel/src/main/java/com/itextpdf/kernel/pdf/PdfPage.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -777,11 +777,18 @@ public List<PdfAnnotation> getAnnotations() {
777777
if (annots != null) {
778778
for (int i = 0; i < annots.size(); i++) {
779779
PdfDictionary annot = annots.getAsDictionary(i);
780+
if (annot == null) {
781+
continue;
782+
}
780783
PdfAnnotation annotation = PdfAnnotation.makeAnnotation(annot);
781-
// PdfAnnotation.makeAnnotation returns null if annotation SubType is not recognized or not present at all
782-
// (although SubType is required according to the spec)
783-
if (annotation != null) {
784-
annotations.add(annotation.setPage(this));
784+
if (annotation == null) {
785+
continue;
786+
}
787+
boolean hasBeenNotModified = annot.getIndirectReference() != null && !annot.getIndirectReference().checkState(PdfObject.MODIFIED);
788+
annotations.add(annotation.setPage(this));
789+
if (hasBeenNotModified) {
790+
annot.getIndirectReference().clearState(PdfObject.MODIFIED);
791+
annot.getIndirectReference().clearState(PdfObject.FORBID_RELEASE);
785792
}
786793
}
787794
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.itextpdf.signatures.sign;
2+
3+
import com.itextpdf.kernel.geom.Rectangle;
4+
import com.itextpdf.kernel.pdf.PdfReader;
5+
import com.itextpdf.kernel.pdf.StampingProperties;
6+
import com.itextpdf.signatures.BouncyCastleDigest;
7+
import com.itextpdf.signatures.DigestAlgorithms;
8+
import com.itextpdf.signatures.IExternalSignature;
9+
import com.itextpdf.signatures.PdfSigner;
10+
import com.itextpdf.signatures.PrivateKeySignature;
11+
import com.itextpdf.signatures.testutils.Pkcs12FileHelper;
12+
import com.itextpdf.test.ExtendedITextTest;
13+
import com.itextpdf.test.annotations.type.IntegrationTest;
14+
import java.io.FileOutputStream;
15+
import java.io.IOException;
16+
import java.security.GeneralSecurityException;
17+
import java.security.PrivateKey;
18+
import java.security.Security;
19+
import java.security.cert.Certificate;
20+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
21+
import org.junit.BeforeClass;
22+
import org.junit.Test;
23+
import org.junit.experimental.categories.Category;
24+
25+
@Category(IntegrationTest.class)
26+
public class SequentialSignaturesTest extends ExtendedITextTest {
27+
private static final String certsSrc = "./src/test/resources/com/itextpdf/signatures/certs/";
28+
private static final String sourceFolder = "./src/test/resources/com/itextpdf/signatures/sign/SequentialSignaturesTest/";
29+
private static final String destinationFolder = "./target/test/com/itextpdf/signatures/sign/SequentialSignaturesTest/";
30+
31+
private static final char[] password = "testpass".toCharArray();
32+
33+
@BeforeClass
34+
public static void before() {
35+
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
36+
createOrClearDestinationFolder(destinationFolder);
37+
}
38+
39+
@Test
40+
public void sequentialSignOfFileWithAnnots() throws IOException, GeneralSecurityException {
41+
String signCertFileName = certsSrc + "signCertRsa01.p12";
42+
String outFileName = destinationFolder + "sequentialSignOfFileWithAnnots.pdf";
43+
String srcFileName = sourceFolder + "signedWithAnnots.pdf";
44+
45+
Certificate[] signChain = Pkcs12FileHelper.readFirstChain(signCertFileName, password);
46+
PrivateKey signPrivateKey = Pkcs12FileHelper.readFirstKey(signCertFileName, password, password);
47+
IExternalSignature pks = new PrivateKeySignature(signPrivateKey, DigestAlgorithms.SHA256, BouncyCastleProvider.PROVIDER_NAME);
48+
49+
String signatureName = "Signature2";
50+
PdfSigner signer = new PdfSigner(new PdfReader(srcFileName), new FileOutputStream(outFileName), new StampingProperties().useAppendMode());
51+
signer.setFieldName(signatureName);
52+
signer.getSignatureAppearance()
53+
.setPageRect(new Rectangle(50, 350, 200, 100))
54+
.setReason("Test")
55+
.setLocation("TestCity")
56+
.setLayer2Text("Approval test signature.\nCreated by iText7.");
57+
58+
signer.signDetached(new BouncyCastleDigest(), pks, signChain, null, null, null, 0, PdfSigner.CryptoStandard.CADES);
59+
60+
PadesSigTest.basicCheckSignedDoc(outFileName, signatureName);
61+
}
62+
}

0 commit comments

Comments
 (0)