Skip to content

Commit e10b046

Browse files
author
Eugene Bochilo
committed
Support signatures prolongation
DEVSIX-7772
1 parent ed6afd8 commit e10b046

19 files changed

+332
-169
lines changed

sharpenConfiguration.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@
471471
</fileset>
472472
<fileset reason="Different implementation on .NET and java">
473473
<file path="com/itextpdf/signatures/sign/IsoSignatureExtensionsRoundtripTest.java"/>
474+
<file path="com/itextpdf/signatures/sign/PdfPadesSignerLevelsTest.java"/>
474475
</fileset>
475476
<fileset reason=".pem files reading logic is different in java and .net">
476477
<file path="com/itextpdf/signatures/testutils/PemFileHelper.java"/>
@@ -570,6 +571,12 @@
570571
<file path="com/itextpdf/signatures/sign/PdfPadesSignerLevelsTest/cmp_padesSignatureLevelTTest1.pdf"/>
571572
<file path="com/itextpdf/signatures/sign/PdfPadesSignerLevelsTest/cmp_padesSignatureLevelTTest2.pdf"/>
572573
<file path="com/itextpdf/signatures/sign/PdfPadesSignerLevelsTest/cmp_padesSignatureLevelTTest3.pdf"/>
574+
<file path="com/itextpdf/signatures/sign/PdfPadesSignerLevelsTest/cmp_prolongDocumentSignaturesTest1.pdf"/>
575+
<file path="com/itextpdf/signatures/sign/PdfPadesSignerLevelsTest/cmp_prolongDocumentSignaturesTest2.pdf"/>
576+
<file path="com/itextpdf/signatures/sign/PdfPadesSignerLevelsTest/cmp_prolongDocumentSignaturesTest3.pdf"/>
577+
<file path="com/itextpdf/signatures/sign/PdfPadesSignerLevelsTest/cmp_prolongDocumentSignaturesTest1_FIPS.pdf"/>
578+
<file path="com/itextpdf/signatures/sign/PdfPadesSignerLevelsTest/cmp_prolongDocumentSignaturesTest2_FIPS.pdf"/>
579+
<file path="com/itextpdf/signatures/sign/PdfPadesSignerLevelsTest/cmp_prolongDocumentSignaturesTest3_FIPS.pdf"/>
573580
<file path="com/itextpdf/signatures/sign/TimestampSigTest/cmp_timestampTest01.pdf"/>
574581
</fileset>
575582
<fileset reason="Bug in java version, not in sharp version, therefor a separate reference file is needed see DEVSIX-6752">

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

Lines changed: 174 additions & 112 deletions
Large diffs are not rendered by default.

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,12 @@ public enum CryptoStandard {
199199
/**
200200
* Holds value of property signDate.
201201
*/
202-
protected Calendar signDate;
202+
protected Calendar signDate = DateTimeUtil.getCurrentTimeCalendar();
203203

204204
/**
205205
* Boolean to check if this PdfSigner instance has been closed already or not.
206206
*/
207-
protected boolean closed;
207+
protected boolean closed = false;
208208

209209
/**
210210
* Creates a PdfSigner instance. Uses a {@link java.io.ByteArrayOutputStream} instead of a temporary file.
@@ -241,12 +241,22 @@ public PdfSigner(PdfReader reader, OutputStream outputStream, String path, Stamp
241241
}
242242

243243
originalOS = outputStream;
244-
signDate = DateTimeUtil.getCurrentTimeCalendar();
245244
fieldName = getNewSigFieldName();
246245
appearance = new PdfSignatureAppearance(document, new Rectangle(0, 0), 1);
247246
appearance.setSignDate(signDate);
248-
249-
closed = false;
247+
}
248+
249+
PdfSigner(PdfDocument document, OutputStream outputStream, ByteArrayOutputStream temporaryOS, File tempFile) {
250+
if (tempFile == null) {
251+
this.temporaryOS = temporaryOS;
252+
} else {
253+
this.tempFile = tempFile;
254+
}
255+
this.document = document;
256+
this.originalOS = outputStream;
257+
this.fieldName = getNewSigFieldName();
258+
this.appearance = new PdfSignatureAppearance(document, new Rectangle(0, 0), 1);
259+
this.appearance.setSignDate(this.signDate);
250260
}
251261

252262
protected PdfDocument initDocument(PdfReader reader, PdfWriter writer, StampingProperties properties) {

sign/src/main/java/com/itextpdf/signatures/exceptions/SignExceptionMessageConstant.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,11 @@ public final class SignExceptionMessageConstant {
4141
+ "signature creation failed. Document shall not contain any certification or approval signatures before "
4242
+ "signing with certification signature.";
4343
public static final String CERTIFICATE_TEMPLATE_FOR_EXCEPTION_MESSAGE = "Certificate {0} failed: {1}";
44+
public static final String DEFAULT_CLIENTS_CANNOT_BE_CREATED = "Default implementation of OCSP and CRL clients "
45+
+ "cannot be created, because signing certificate doesn't contain revocation data sources. "
46+
+ "Please try to explicitly add OCSP or CRL client.";
4447
public static final String DICTIONARY_THIS_KEY_IS_NOT_A_NAME = "Dictionary key {0} is not a name.";
4548
public static final String DOCUMENT_ALREADY_PRE_CLOSED = "Document has been already pre closed.";
46-
public static final String DOCUMENT_CANNOT_BE_SIGNED = "Document cannot be signed with this PaDES profile level, "
47-
+ "because {0} is null. Please, provide {0} using corresponding setter method.";
4849
public static final String DOCUMENT_MUST_BE_PRE_CLOSED = "Document must be preClosed.";
4950
public static final String DOCUMENT_MUST_HAVE_READER = "Document must have reader.";
5051
public static final String FAILED_TO_GET_TSA_RESPONSE = "Failed to get TSA response from {0}.";
@@ -56,6 +57,7 @@ public final class SignExceptionMessageConstant {
5657
+ "certificate chain.";
5758
public static final String INVALID_TSA_RESPONSE = "Invalid TSA {0} response code {1}.";
5859
public static final String NO_CRYPTO_DICTIONARY_DEFINED = "No crypto dictionary defined.";
60+
public static final String NO_SIGNATURES_TO_PROLONG = "Document doesn't contain any signatures to prolong.";
5961
public static final String NOT_A_VALID_PKCS7_OBJECT_NOT_A_SEQUENCE = "Not a valid PKCS#7 object - not a sequence";
6062
public static final String NOT_A_VALID_PKCS7_OBJECT_NOT_SIGNED_DATA = "Not a valid PKCS#7 object - not signed "
6163
+ "data.";

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

Lines changed: 72 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ This file is part of the iText (R) project.
2626
import com.itextpdf.commons.bouncycastle.IBouncyCastleFactory;
2727
import com.itextpdf.commons.bouncycastle.operator.AbstractOperatorCreationException;
2828
import com.itextpdf.commons.bouncycastle.pkcs.AbstractPKCSException;
29+
import com.itextpdf.commons.utils.FileUtil;
2930
import com.itextpdf.kernel.geom.Rectangle;
3031
import com.itextpdf.kernel.pdf.PdfReader;
3132
import com.itextpdf.kernel.pdf.StampingProperties;
@@ -42,9 +43,7 @@ This file is part of the iText (R) project.
4243
import com.itextpdf.signatures.testutils.client.TestTsaClient;
4344
import com.itextpdf.test.ExtendedITextTest;
4445
import com.itextpdf.test.annotations.type.BouncyCastleIntegrationTest;
45-
import com.itextpdf.test.annotations.type.IntegrationTest;
4646

47-
import java.io.FileOutputStream;
4847
import java.io.IOException;
4948
import java.security.GeneralSecurityException;
5049
import java.security.PrivateKey;
@@ -65,6 +64,8 @@ public class PdfPadesSignerLevelsTest extends ExtendedITextTest {
6564

6665
private static final IBouncyCastleFactory FACTORY = BouncyCastleFactoryCreator.getFactory();
6766

67+
private static final boolean FIPS_MODE = "BCFIPS".equals(FACTORY.getProviderName());
68+
6869
private static final String certsSrc = "./src/test/resources/com/itextpdf/signatures/certs/";
6970
private static final String sourceFolder = "./src/test/resources/com/itextpdf/signatures/sign/PdfPadesSignerLevelsTest/";
7071
private static final String destinationFolder = "./target/test/com/itextpdf/signatures/sign/PdfPadesSignerLevelsTest/";
@@ -87,7 +88,7 @@ public PdfPadesSignerLevelsTest(Object useTempFolder, Object useSignature, Objec
8788
this.comparisonPdfId = (Integer) comparisonPdfId;
8889
}
8990

90-
@Parameterized.Parameters(name = "{index}: folder path: {0}; pass whole signature: {1}")
91+
@Parameterized.Parameters(name = "{2}: folder path: {0}; pass whole signature: {1}")
9192
public static Iterable<Object[]> createParameters() {
9293
return Arrays.asList(new Object[] {true, true, 1},
9394
new Object[] {false, true, 2},
@@ -105,16 +106,20 @@ public void padesSignatureLevelBTest()
105106

106107
Certificate[] signRsaChain = PemFileHelper.readFirstChain(signCertFileName);
107108
PrivateKey signRsaPrivateKey = PemFileHelper.readFirstKey(signCertFileName, password);
108-
IExternalSignature pks =
109-
new PrivateKeySignature(signRsaPrivateKey, DigestAlgorithms.SHA256, FACTORY.getProviderName());
110109

111110
PdfSigner signer = createPdfSigner(srcFileName, outFileName);
112111

113-
PdfPadesSigner padesSigner = createPdfPadesSigner(signer, pks, signRsaPrivateKey);
112+
PdfPadesSigner padesSigner = new PdfPadesSigner();
114113
if ((boolean) useTempFolder) {
115114
padesSigner.setTemporaryDirectoryPath(destinationFolder);
116115
}
117-
padesSigner.signWithBaselineBProfile(signRsaChain);
116+
if ((boolean) useSignature) {
117+
IExternalSignature pks =
118+
new PrivateKeySignature(signRsaPrivateKey, DigestAlgorithms.SHA256, FACTORY.getProviderName());
119+
padesSigner.signWithBaselineBProfile(signer, signRsaChain, pks);
120+
} else {
121+
padesSigner.signWithBaselineBProfile(signer, signRsaChain, signRsaPrivateKey);
122+
}
118123

119124
PadesSigTest.basicCheckSignedDoc(outFileName, "Signature1");
120125

@@ -133,21 +138,24 @@ public void padesSignatureLevelTTest()
133138

134139
Certificate[] signRsaChain = PemFileHelper.readFirstChain(signCertFileName);
135140
PrivateKey signRsaPrivateKey = PemFileHelper.readFirstKey(signCertFileName, password);
136-
IExternalSignature pks =
137-
new PrivateKeySignature(signRsaPrivateKey, DigestAlgorithms.SHA256, FACTORY.getProviderName());
138141
Certificate[] tsaChain = PemFileHelper.readFirstChain(tsaCertFileName);
139142
PrivateKey tsaPrivateKey = PemFileHelper.readFirstKey(tsaCertFileName, password);
140143

141144
PdfSigner signer = createPdfSigner(srcFileName, outFileName);
142145

143146
TestTsaClient testTsa = new TestTsaClient(Arrays.asList(tsaChain), tsaPrivateKey);
144147

145-
PdfPadesSigner padesSigner = createPdfPadesSigner(signer, pks, signRsaPrivateKey);
148+
PdfPadesSigner padesSigner = new PdfPadesSigner();
146149
if ((boolean) useTempFolder) {
147150
padesSigner.setTemporaryDirectoryPath(destinationFolder);
148151
}
149-
padesSigner.setTsaClient(testTsa);
150-
padesSigner.signWithBaselineTProfile(signRsaChain);
152+
if ((boolean) useSignature) {
153+
IExternalSignature pks =
154+
new PrivateKeySignature(signRsaPrivateKey, DigestAlgorithms.SHA256, FACTORY.getProviderName());
155+
padesSigner.signWithBaselineTProfile(signer, signRsaChain, pks, testTsa);
156+
} else {
157+
padesSigner.signWithBaselineTProfile(signer, signRsaChain, signRsaPrivateKey, testTsa);
158+
}
151159

152160
PadesSigTest.basicCheckSignedDoc(outFileName, "Signature1");
153161

@@ -167,8 +175,6 @@ public void padesSignatureLevelLTTest()
167175

168176
Certificate[] signRsaChain = PemFileHelper.readFirstChain(signCertFileName);
169177
PrivateKey signRsaPrivateKey = PemFileHelper.readFirstKey(signCertFileName, password);
170-
IExternalSignature pks =
171-
new PrivateKeySignature(signRsaPrivateKey, DigestAlgorithms.SHA256, FACTORY.getProviderName());
172178
Certificate[] tsaChain = PemFileHelper.readFirstChain(tsaCertFileName);
173179
PrivateKey tsaPrivateKey = PemFileHelper.readFirstKey(tsaCertFileName, password);
174180
X509Certificate caCert = (X509Certificate) PemFileHelper.readFirstChain(caCertFileName)[0];
@@ -180,12 +186,18 @@ public void padesSignatureLevelLTTest()
180186
ICrlClient crlClient = new TestCrlClient().addBuilderForCertIssuer(caCert, caPrivateKey);
181187
TestOcspClient ocspClient = new TestOcspClient().addBuilderForCertIssuer(caCert, caPrivateKey);
182188

183-
PdfPadesSigner padesSigner = createPdfPadesSigner(signer, pks, signRsaPrivateKey);
189+
PdfPadesSigner padesSigner = new PdfPadesSigner();
184190
if ((boolean) useTempFolder) {
185191
padesSigner.setTemporaryDirectoryPath(destinationFolder);
186192
}
187-
padesSigner.setTsaClient(testTsa).setOcspClient(ocspClient).setCrlClient(crlClient);
188-
padesSigner.signWithBaselineLTProfile(signRsaChain);
193+
padesSigner.setOcspClient(ocspClient).setCrlClient(crlClient);
194+
if ((boolean) useSignature) {
195+
IExternalSignature pks =
196+
new PrivateKeySignature(signRsaPrivateKey, DigestAlgorithms.SHA256, FACTORY.getProviderName());
197+
padesSigner.signWithBaselineLTProfile(signer, signRsaChain, pks, testTsa);
198+
} else {
199+
padesSigner.signWithBaselineLTProfile(signer, signRsaChain, signRsaPrivateKey, testTsa);
200+
}
189201

190202
PadesSigTest.basicCheckSignedDoc(outFileName, "Signature1");
191203

@@ -205,8 +217,6 @@ public void padesSignatureLevelLTATest()
205217

206218
Certificate[] signRsaChain = PemFileHelper.readFirstChain(signCertFileName);
207219
PrivateKey signRsaPrivateKey = PemFileHelper.readFirstKey(signCertFileName, password);
208-
IExternalSignature pks =
209-
new PrivateKeySignature(signRsaPrivateKey, DigestAlgorithms.SHA256, FACTORY.getProviderName());
210220
Certificate[] tsaChain = PemFileHelper.readFirstChain(tsaCertFileName);
211221
PrivateKey tsaPrivateKey = PemFileHelper.readFirstKey(tsaCertFileName, password);
212222
X509Certificate caCert = (X509Certificate) PemFileHelper.readFirstChain(caCertFileName)[0];
@@ -218,29 +228,64 @@ public void padesSignatureLevelLTATest()
218228
ICrlClient crlClient = new TestCrlClient().addBuilderForCertIssuer(caCert, caPrivateKey);
219229
TestOcspClient ocspClient = new TestOcspClient().addBuilderForCertIssuer(caCert, caPrivateKey);
220230

221-
PdfPadesSigner padesSigner = createPdfPadesSigner(signer, pks, signRsaPrivateKey);
231+
PdfPadesSigner padesSigner = new PdfPadesSigner();
222232
if ((boolean) useTempFolder) {
223233
padesSigner.setTemporaryDirectoryPath(destinationFolder);
224234
}
225-
padesSigner.setTsaClient(testTsa).setOcspClient(ocspClient).setCrlClient(crlClient)
235+
padesSigner.setOcspClient(ocspClient).setCrlClient(crlClient)
226236
.setTimestampSignatureName("timestampSig1");
227-
padesSigner.signWithBaselineLTAProfile(signRsaChain);
237+
if ((boolean) useSignature) {
238+
IExternalSignature pks =
239+
new PrivateKeySignature(signRsaPrivateKey, DigestAlgorithms.SHA256, FACTORY.getProviderName());
240+
padesSigner.signWithBaselineLTAProfile(signer, signRsaChain, pks, testTsa);
241+
} else {
242+
padesSigner.signWithBaselineLTAProfile(signer, signRsaChain, signRsaPrivateKey, testTsa);
243+
}
228244

229245
PadesSigTest.basicCheckSignedDoc(outFileName, "Signature1");
230246

231247
Assert.assertNull(SignaturesCompareTool.compareSignatures(outFileName, cmpFileName));
232248
}
233249

234-
private PdfPadesSigner createPdfPadesSigner(PdfSigner signer, IExternalSignature externalSignature,
235-
PrivateKey privateKey) {
250+
@Test
251+
public void prolongDocumentSignaturesTest()
252+
throws GeneralSecurityException, IOException, AbstractOperatorCreationException, AbstractPKCSException {
253+
String fileName = "prolongDocumentSignaturesTest" + comparisonPdfId + (FIPS_MODE ? "_FIPS.pdf" : ".pdf");
254+
String outFileName = destinationFolder + fileName;
255+
String cmpFileName = sourceFolder + "cmp_" + fileName;
256+
String srcFileName = sourceFolder + "padesSignatureLevelLTA.pdf";
257+
String tsaCertFileName = certsSrc + "tsCertRsa.pem";
258+
String caCertFileName = certsSrc + "rootRsa.pem";
259+
260+
Certificate[] tsaChain = PemFileHelper.readFirstChain(tsaCertFileName);
261+
PrivateKey tsaPrivateKey = PemFileHelper.readFirstKey(tsaCertFileName, password);
262+
X509Certificate caCert = (X509Certificate) PemFileHelper.readFirstChain(caCertFileName)[0];
263+
PrivateKey caPrivateKey = PemFileHelper.readFirstKey(caCertFileName, password);
264+
265+
TestTsaClient testTsa = new TestTsaClient(Arrays.asList(tsaChain), tsaPrivateKey);
266+
ICrlClient crlClient = new TestCrlClient().addBuilderForCertIssuer(caCert, caPrivateKey);
267+
TestOcspClient ocspClient = new TestOcspClient().addBuilderForCertIssuer(caCert, caPrivateKey);
268+
269+
PdfPadesSigner padesSigner = new PdfPadesSigner();
270+
if ((boolean) useTempFolder) {
271+
padesSigner.setTemporaryDirectoryPath(destinationFolder);
272+
}
273+
padesSigner.setOcspClient(ocspClient).setCrlClient(crlClient);
236274
if ((boolean) useSignature) {
237-
return new PdfPadesSigner(signer, externalSignature);
275+
padesSigner.prolongSignatures(new PdfReader(FileUtil.getInputStreamForFile(srcFileName)),
276+
FileUtil.getFileOutputStream(outFileName), testTsa);
277+
} else {
278+
padesSigner.prolongSignatures(new PdfReader(FileUtil.getInputStreamForFile(srcFileName)),
279+
FileUtil.getFileOutputStream(outFileName));
238280
}
239-
return new PdfPadesSigner(signer, privateKey);
281+
282+
PadesSigTest.basicCheckSignedDoc(outFileName, "Signature1");
283+
Assert.assertNull(SignaturesCompareTool.compareSignatures(outFileName, cmpFileName));
240284
}
241285

242286
private PdfSigner createPdfSigner(String srcFileName, String outFileName) throws IOException {
243-
PdfSigner signer = new PdfSigner(new PdfReader(srcFileName), new FileOutputStream(outFileName), new StampingProperties());
287+
PdfSigner signer = new PdfSigner(new PdfReader(srcFileName), FileUtil.getFileOutputStream(outFileName),
288+
new StampingProperties());
244289
signer.setFieldName("Signature1");
245290
signer.getSignatureAppearance()
246291
.setPageRect(new Rectangle(50, 650, 200, 100))

0 commit comments

Comments
 (0)