-
Notifications
You must be signed in to change notification settings - Fork 99
Expand file tree
/
Copy pathSignatureExample.java
More file actions
165 lines (135 loc) · 6.26 KB
/
SignatureExample.java
File metadata and controls
165 lines (135 loc) · 6.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package com.itextpdf.samples.sandbox.signatures;
import com.itextpdf.forms.form.element.SignatureFieldAppearance;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.crypto.DigestAlgorithms;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.AccessPermissions;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.CrlClientOnline;
import com.itextpdf.signatures.ICrlClient;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.OcspClientBouncyCastle;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import com.itextpdf.signatures.SignerProperties;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class SignatureExample {
public static final String DEST = "./target/sandbox/signatures/signExample.pdf";
public static final String SRC = "./src/main/resources/pdfs/signExample.pdf";
public static final String CERT_PATH = "./src/main/resources/cert/signCertRsa01.p12";
public static final String IMAGE_PATH = "./src/main/resources/img/sign.jpg";
public static void main(String[] args) throws Exception {
File file = new File(DEST);
file.getParentFile().mkdirs();
new SignatureExample().manipulatePdf(DEST);
}
protected void manipulatePdf(String dest) throws Exception {
ElectronicSignatureInfoDTO signatureInfo = new ElectronicSignatureInfoDTO();
signatureInfo.setBottom(25);
signatureInfo.setLeft(25);
signatureInfo.setPageNumber(1);
SignDocumentSignature(dest, signatureInfo);
}
protected void SignDocumentSignature(String filePath, ElectronicSignatureInfoDTO signatureInfo)
throws Exception {
PdfSigner pdfSigner = new PdfSigner(new PdfReader(SRC), new FileOutputStream(filePath),
new StampingProperties());
SignerProperties signerProperties = new SignerProperties();
signerProperties.setCertificationLevel(AccessPermissions.NO_CHANGES_PERMITTED);
// Set the name indicating the field to be signed.
// The field can already be present in the document but shall not be signed
signerProperties.setFieldName("signature");
pdfSigner.setSignerProperties(signerProperties);
ImageData clientSignatureImage = ImageDataFactory.create(IMAGE_PATH);
// If you create new signature field (or use SignerProperties#setFieldName with
// the name that doesn't exist in the document or don't specify it at all) then
// the signature is invisible by default.
SignatureFieldAppearance signatureAppearance = new SignatureFieldAppearance(SignerProperties.IGNORED_ID)
.setContent(clientSignatureImage);
signerProperties.setPageNumber(signatureInfo.getPageNumber())
.setPageRect(new Rectangle(signatureInfo.getLeft(), signatureInfo.getBottom(), 25, 25))
.setSignatureAppearance(signatureAppearance);
char[] password = "testpass".toCharArray();
IExternalSignature pks = getPrivateKeySignature(CERT_PATH, password);
Certificate[] chain = getCertificateChain(CERT_PATH, password);
OcspClientBouncyCastle ocspClient = new OcspClientBouncyCastle();
List<ICrlClient> crlClients = Arrays.asList((ICrlClient) new CrlClientOnline());
// Sign the document using the detached mode, CMS or CAdES equivalent.
// This method closes the underlying pdf document, so the instance
// of PdfSigner cannot be used after this method call
pdfSigner.signDetached(new BouncyCastleDigest(), pks, chain, crlClients, ocspClient, null,
0, PdfSigner.CryptoStandard.CMS);
}
/**
* Method reads pkcs12 file's first private key and returns {@link PrivateKeySignature} instance,
* which uses SHA-512 hash algorithm.
*/
private PrivateKeySignature getPrivateKeySignature(String certificatePath, char[] password) throws Exception {
PrivateKey pk = null;
KeyStore p12 = KeyStore.getInstance("pkcs12");
p12.load(new FileInputStream(certificatePath), password);
Enumeration<String> aliases = p12.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (p12.isKeyEntry(alias)) {
pk = (PrivateKey) p12.getKey(alias, password);
break;
}
}
Security.addProvider(new BouncyCastleProvider());
return new PrivateKeySignature(pk, DigestAlgorithms.SHA512, BouncyCastleProvider.PROVIDER_NAME);
}
/**
* Method reads first public certificate chain
*/
private Certificate[] getCertificateChain(String certificatePath, char[] password) throws Exception {
Certificate[] certChain = null;
KeyStore p12 = KeyStore.getInstance("pkcs12");
p12.load(new FileInputStream(certificatePath), password);
Enumeration<String> aliases = p12.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (p12.isKeyEntry(alias)) {
certChain = p12.getCertificateChain(alias);
break;
}
}
return certChain;
}
protected class ElectronicSignatureInfoDTO {
private int pageNumber;
private float left;
private float bottom;
public int getPageNumber() {
return pageNumber;
}
public void setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
}
public float getLeft() {
return left;
}
public void setLeft(float left) {
this.left = left;
}
public float getBottom() {
return bottom;
}
public void setBottom(float bottom) {
this.bottom = bottom;
}
}
}