Skip to content

Commit 753f4d3

Browse files
Improve documentation and naming for signature integrity, authenticity and document coverage checks
DEVSIX-2744
1 parent 121daf7 commit 753f4d3

File tree

7 files changed

+121
-28
lines changed

7 files changed

+121
-28
lines changed

sign/src/main/java/com/itextpdf/signatures/LtvVerification.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ public LtvVerification(PdfDocument document, String securityProviderCode){
193193
public boolean addVerification(String signatureName, IOcspClient ocsp, ICrlClient crl, CertificateOption certOption, Level level, CertificateInclusion certInclude) throws IOException, GeneralSecurityException {
194194
if (used)
195195
throw new IllegalStateException(PdfException.VerificationAlreadyOutput);
196-
PdfPKCS7 pk = sgnUtil.verifySignature(signatureName, securityProviderCode);
196+
PdfPKCS7 pk = sgnUtil.readSignatureData(signatureName, securityProviderCode);
197197
LOGGER.info("Adding verification for " + signatureName);
198198
Certificate[] xc = pk.getCertificates();
199199
X509Certificate cert;

sign/src/main/java/com/itextpdf/signatures/LtvVerifier.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,14 +364,14 @@ protected void initLtvVerifier(PdfDocument document) throws GeneralSecurityExcep
364364
* @throws GeneralSecurityException
365365
*/
366366
protected PdfPKCS7 coversWholeDocument() throws GeneralSecurityException {
367-
PdfPKCS7 pkcs7 = sgnUtil.verifySignature(signatureName, securityProviderCode);
367+
PdfPKCS7 pkcs7 = sgnUtil.readSignatureData(signatureName, securityProviderCode);
368368
if (sgnUtil.signatureCoversWholeDocument(signatureName)) {
369369
LOGGER.info("The timestamp covers whole document.");
370370
}
371371
else {
372372
throw new VerificationException((Certificate) null, "Signature doesn't cover whole document.");
373373
}
374-
if (pkcs7.verify()) {
374+
if (pkcs7.verifySignatureIntegrityAndAuthenticity()) {
375375
LOGGER.info("The signed document has not been modified.");
376376
return pkcs7;
377377
}

sign/src/main/java/com/itextpdf/signatures/PdfPKCS7.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,10 +1162,34 @@ private DERSet getAuthenticatedAttributeSet(byte[] secondDigest, Collection<byte
11621162
* Verify the digest.
11631163
*
11641164
* @return <CODE>true</CODE> if the signature checks out, <CODE>false</CODE> otherwise
1165-
* @throws SignatureException on error
1166-
* @throws java.security.GeneralSecurityException
1165+
* @throws java.security.GeneralSecurityException if this signature object is not initialized properly,
1166+
* the passed-in signature is improperly encoded or of the wrong type, if this signature algorithm is unable to
1167+
* process the input data provided, if the public key is invalid or if security provider or signature algorithm
1168+
* are not recognized, etc.
1169+
* @deprecated This method will be removed in future versions. Please use {@link #verifySignatureIntegrityAndAuthenticity()} instead.
11671170
*/
1171+
@Deprecated
11681172
public boolean verify() throws GeneralSecurityException {
1173+
return verifySignatureIntegrityAndAuthenticity();
1174+
}
1175+
1176+
/**
1177+
* Verifies that signature integrity is intact (or in other words that signed data wasn't modified)
1178+
* by checking that embedded data digest corresponds to the calculated one. Also ensures that signature
1179+
* is genuine and is created by the owner of private key that corresponds to the declared public certificate.
1180+
* <p>
1181+
* Even though signature can be authentic and signed data integrity can be intact,
1182+
* one shall also always check that signed data is not only a part of PDF contents but is actually a complete PDF file.
1183+
* In order to check that given signature covers the current {@link com.itextpdf.kernel.pdf.PdfDocument} please
1184+
* use {@link SignatureUtil#signatureCoversWholeDocument(String)} method.
1185+
* </p>
1186+
* @return <CODE>true</CODE> if the signature checks out, <CODE>false</CODE> otherwise
1187+
* @throws java.security.GeneralSecurityException if this signature object is not initialized properly,
1188+
* the passed-in signature is improperly encoded or of the wrong type, if this signature algorithm is unable to
1189+
* process the input data provided, if the public key is invalid or if security provider or signature algorithm
1190+
* are not recognized, etc.
1191+
*/
1192+
public boolean verifySignatureIntegrityAndAuthenticity() throws GeneralSecurityException {
11691193
if (verified)
11701194
return verifyResult;
11711195
if (isTsp) {

sign/src/main/java/com/itextpdf/signatures/SignatureUtil.java

Lines changed: 82 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -116,26 +116,91 @@ public SignatureUtil(PdfDocument document) {
116116
}
117117

118118
/**
119-
* Verifies a signature. Further verification can be done on the returned
120-
* {@link PdfPKCS7} object.
119+
* Prepares an {@link PdfPKCS7} instance for the given signature.
120+
* This method handles signature parsing and might throw an exception if
121+
* signature is malformed.
122+
* <p>
123+
* The returned {@link PdfPKCS7} can be used to fetch additional info about the signature
124+
* and also to perform integrity check of data signed by the given signature field.
125+
* </p>
126+
* In order to check that given signature covers the current PdfDocument revision please
127+
* use {@link #signatureCoversWholeDocument(String)} method.
121128
*
122-
* @param name String the signature field name
123-
* @return PdfPKCS7 object to continue the verification
129+
* @param name the signature field name
130+
* @return a {@link PdfPKCS7} instance which can be used to fetch additional info about the signature
131+
* and also to perform integrity check of data signed by the given signature field.
132+
* @deprecated This method is deprecated and will be removed in future versions.
133+
* Please use {@link #readSignatureData(String)} instead.
124134
*/
135+
@Deprecated
125136
public PdfPKCS7 verifySignature(String name) {
126-
return verifySignature(name, null);
137+
return readSignatureData(name, null);
127138
}
128139

129140
/**
130-
* Verifies a signature. Further verification can be done on the returned
131-
* {@link PdfPKCS7} object.
141+
* Prepares an {@link PdfPKCS7} instance for the given signature.
142+
* This method handles signature parsing and might throw an exception if
143+
* signature is malformed.
144+
* <p>
145+
* The returned {@link PdfPKCS7} can be used to fetch additional info about the signature
146+
* and also to perform integrity check of data signed by the given signature field.
147+
* </p>
148+
* In order to check that given signature covers the current PdfDocument revision please
149+
* use {@link #signatureCoversWholeDocument(String)} method.
132150
*
133151
* @param name the signature field name
134-
* @param provider the provider or null for the default provider
135-
* @return PdfPKCS7 object to continue the verification
152+
* @param provider the security provider or null for the default provider
153+
* @return a {@link PdfPKCS7} instance which can be used to fetch additional info about the signature
154+
* and also to perform integrity check of data signed by the given signature field.
155+
* @deprecated This method is deprecated and will be removed in future versions.
156+
* Please use {@link #readSignatureData(String, String)} instead.
136157
*/
158+
@Deprecated
137159
public PdfPKCS7 verifySignature(String name, String provider) {
138-
PdfSignature signature = getSignature(name);
160+
return readSignatureData(name, provider);
161+
}
162+
163+
/**
164+
* Prepares an {@link PdfPKCS7} instance for the given signature.
165+
* This method handles signature parsing and might throw an exception if
166+
* signature is malformed.
167+
* <p>
168+
* The returned {@link PdfPKCS7} can be used to fetch additional info about the signature
169+
* and also to perform integrity check of data signed by the given signature field.
170+
* </p>
171+
* In order to validate the signature it is required to check if it covers the entire file,
172+
* otherwise one cannot be sure that signature in question indeed signs the data
173+
* that constitutes current {@link PdfDocument} with all its contents.
174+
* In order to check that given signature covers the current {@link PdfDocument} please
175+
* use {@link #signatureCoversWholeDocument(String)} method.
176+
*
177+
* @param signatureFieldName the signature field name
178+
* @return a {@link PdfPKCS7} instance which can be used to fetch additional info about the signature
179+
* and also to perform integrity check of data signed by the given signature field.
180+
*/
181+
public PdfPKCS7 readSignatureData(String signatureFieldName) {
182+
return readSignatureData(signatureFieldName, null);
183+
}
184+
185+
/**
186+
* Prepares an {@link PdfPKCS7} instance for the given signature.
187+
* This method handles signature parsing and might throw an exception if
188+
* signature is malformed.
189+
* <p>
190+
* The returned {@link PdfPKCS7} can be used to fetch additional info about the signature
191+
* and also to perform integrity check of data signed by the given signature field.
192+
* </p>
193+
* Prepared {@link PdfPKCS7} instance calculates digest based on signature's /ByteRange entry.
194+
* In order to check that /ByteRange is properly defined and given signature indeed covers the current PDF document
195+
* revision please use {@link #signatureCoversWholeDocument(String)} method.
196+
*
197+
* @param signatureFieldName the signature field name
198+
* @param securityProvider the security provider or null for the default provider
199+
* @return a {@link PdfPKCS7} instance which can be used to fetch additional info about the signature
200+
* and also to perform integrity check of data signed by the given signature field.
201+
*/
202+
public PdfPKCS7 readSignatureData(String signatureFieldName, String securityProvider) {
203+
PdfSignature signature = getSignature(signatureFieldName);
139204
if (signature == null)
140205
return null;
141206
try {
@@ -146,9 +211,9 @@ public PdfPKCS7 verifySignature(String name, String provider) {
146211
PdfString cert = signature.getPdfObject().getAsString(PdfName.Cert);
147212
if (cert == null)
148213
cert = signature.getPdfObject().getAsArray(PdfName.Cert).getAsString(0);
149-
pk = new PdfPKCS7(PdfEncodings.convertToBytes(contents.getValue(), null), cert.getValueBytes(), provider);
214+
pk = new PdfPKCS7(PdfEncodings.convertToBytes(contents.getValue(), null), cert.getValueBytes(), securityProvider);
150215
} else
151-
pk = new PdfPKCS7(PdfEncodings.convertToBytes(contents.getValue(), null), sub, provider);
216+
pk = new PdfPKCS7(PdfEncodings.convertToBytes(contents.getValue(), null), sub, securityProvider);
152217
updateByteRange(pk, signature);
153218
PdfString date = signature.getDate();
154219
if (date != null)
@@ -289,7 +354,11 @@ public InputStream extractRevision(String field) throws IOException {
289354

290355
/**
291356
* Checks if the signature covers the entire document (except for signature's Contents) or just a part of it.
292-
*
357+
* <p>
358+
* If this method does not return {@code true} it means that signature in question does not cover the entire
359+
* contents of current {@link PdfDocument}. Such signatures cannot be considered as verifying the PDF document,
360+
* because content that is not covered by signature might have been modified since the signature creation.
361+
* </p>
293362
* @param name the signature field name
294363
* @return true if the signature covers the entire document, false if it doesn't
295364
*/

sign/src/test/java/com/itextpdf/signatures/sign/PadesSigTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,8 @@ static void basicCheckSignedDoc(String filePath, String signatureName) throws Ge
169169
PdfDocument outDocument = new PdfDocument(new PdfReader(filePath));
170170

171171
SignatureUtil sigUtil = new SignatureUtil(outDocument);
172-
PdfPKCS7 pdfPKCS7 = sigUtil.verifySignature(signatureName);
173-
Assert.assertTrue(pdfPKCS7.verify());
172+
PdfPKCS7 signatureData = sigUtil.readSignatureData(signatureName);
173+
Assert.assertTrue(signatureData.verifySignatureIntegrityAndAuthenticity());
174174

175175
outDocument.close();
176176
}

sign/src/test/java/com/itextpdf/signatures/verify/pdfinsecurity/IncrementalSavingAttackTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ public void testISA03() throws IOException, GeneralSecurityException {
3838

3939
PdfDocument document = new PdfDocument(new PdfReader(filePath));
4040
SignatureUtil sigUtil = new SignatureUtil(document);
41-
PdfPKCS7 pdfPKCS7 = sigUtil.verifySignature(signatureName);
42-
Assert.assertTrue(pdfPKCS7.verify());
41+
PdfPKCS7 pdfPKCS7 = sigUtil.readSignatureData(signatureName);
42+
Assert.assertTrue(pdfPKCS7.verifySignatureIntegrityAndAuthenticity());
4343
Assert.assertFalse(sigUtil.signatureCoversWholeDocument(signatureName));
4444
document.close();
4545
}
@@ -51,8 +51,8 @@ public void testISAValidPdf() throws IOException, GeneralSecurityException {
5151

5252
PdfDocument document = new PdfDocument(new PdfReader(filePath));
5353
SignatureUtil sigUtil = new SignatureUtil(document);
54-
PdfPKCS7 pdfPKCS7 = sigUtil.verifySignature(signatureName);
55-
Assert.assertTrue(pdfPKCS7.verify());
54+
PdfPKCS7 pdfPKCS7 = sigUtil.readSignatureData(signatureName);
55+
Assert.assertTrue(pdfPKCS7.verifySignatureIntegrityAndAuthenticity());
5656
Assert.assertFalse(sigUtil.signatureCoversWholeDocument(signatureName));
5757

5858
String textFromPage = PdfTextExtractor.getTextFromPage(document.getPage(1));
@@ -68,8 +68,8 @@ public void testISAValidPdf() throws IOException, GeneralSecurityException {
6868
PdfDocument sigRevDocument = new PdfDocument(new PdfReader(sigInputStream));
6969

7070
SignatureUtil sigRevUtil = new SignatureUtil(sigRevDocument);
71-
PdfPKCS7 sigRevSignatureData = sigRevUtil.verifySignature(signatureName);
72-
Assert.assertTrue(sigRevSignatureData.verify());
71+
PdfPKCS7 sigRevSignatureData = sigRevUtil.readSignatureData(signatureName);
72+
Assert.assertTrue(sigRevSignatureData.verifySignatureIntegrityAndAuthenticity());
7373
Assert.assertTrue(sigRevUtil.signatureCoversWholeDocument(signatureName));
7474

7575
sigRevDocument.close();

sign/src/test/java/com/itextpdf/signatures/verify/pdfinsecurity/SignatureWrappingAttackTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ public void testSWA01() throws IOException, GeneralSecurityException {
3131

3232
PdfDocument document = new PdfDocument(new PdfReader(filePath));
3333
SignatureUtil sigUtil = new SignatureUtil(document);
34-
PdfPKCS7 pdfPKCS7 = sigUtil.verifySignature(signatureName);
35-
Assert.assertTrue(pdfPKCS7.verify());
34+
PdfPKCS7 pdfPKCS7 = sigUtil.readSignatureData(signatureName);
35+
Assert.assertTrue(pdfPKCS7.verifySignatureIntegrityAndAuthenticity());
3636
Assert.assertFalse(sigUtil.signatureCoversWholeDocument(signatureName));
3737
document.close();
3838
}

0 commit comments

Comments
 (0)