iText pdf library
Website search

Digital signatures - chapter 4

These examples were written in the context of Chapter 4 - "Creating signatures externally" of the Digital Signatures for PDF documents eBook.

C4_01_SignWithPKCS11HSM.java
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
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2020 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
/*
 * This class is part of the white paper entitled
 * "Digital Signatures for PDF documents"
 * written by Bruno Lowagie
 *
 * For more info, go to: http://itextpdf.com/learn
 */
package com.itextpdf.samples.signatures.chapter04;
 
import sun.security.pkcs11.SunPKCS11;
 
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.CertificateUtil;
import com.itextpdf.signatures.ICrlClient;
import com.itextpdf.signatures.CrlClientOnline;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.IOcspClient;
import com.itextpdf.signatures.OcspClientBouncyCastle;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import com.itextpdf.signatures.ITSAClient;
import com.itextpdf.signatures.TSAClientBouncyCastle;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
 
import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
public class C4_01_SignWithPKCS11HSM {
    public static final String DEST = "./target/signatures/chapter04/";
 
    public static final String SRC = "./src/test/resources/pdfs/hello.pdf";
 
    public static final String[] RESULT_FILES = new String[] {
            "hello_hsm.pdf"
    };
 
    public static void main(String[] args) throws IOException, GeneralSecurityException {
        File file = new File(DEST);
        file.mkdirs();
 
        Properties properties = new Properties();
 
        // Specify the correct path to the certificate
        properties.load(new FileInputStream("C:/signkey.properties"));
        char[] pass = properties.getProperty("PASSWORD").toCharArray();
        String pkcs11cfg = properties.getProperty("PKCS11CFG");
 
        BouncyCastleProvider providerBC = new BouncyCastleProvider();
        Security.addProvider(providerBC);
        FileInputStream fis = new FileInputStream(pkcs11cfg);
        Provider providerPKCS11 = new SunPKCS11(fis);
        Security.addProvider(providerPKCS11);
 
        KeyStore ks = KeyStore.getInstance("PKCS11");
        ks.load(null, pass);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, pass);
        Certificate[] chain = ks.getCertificateChain(alias);
        IOcspClient ocspClient = new OcspClientBouncyCastle(null);
        ITSAClient tsaClient = null;
        for (int i = 0; i < chain.length; i++) {
            X509Certificate cert = (X509Certificate) chain[i];
            String tsaUrl = CertificateUtil.getTSAURL(cert);
            if (tsaUrl != null) {
                tsaClient = new TSAClientBouncyCastle(tsaUrl);
                break;
            }
        }
 
        List<ICrlClient> crlList = new ArrayList<ICrlClient>();
        crlList.add(new CrlClientOnline(chain));
 
        new C4_01_SignWithPKCS11HSM().sign(SRC, DEST + RESULT_FILES[0], chain, pk,
                DigestAlgorithms.SHA256, providerPKCS11.getName(), PdfSigner.CryptoStandard.CMS,
                "HSM test", "Ghent", crlList, ocspClient, tsaClient, 0);
    }
 
    public void sign(String src, String dest, Certificate[] chain, PrivateKey pk,
            String digestAlgorithm, String provider, PdfSigner.CryptoStandard subfilter,
            String reason, String location, Collection<ICrlClient> crlList,
            IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
 
        // Create the signature appearance
        Rectangle rect = new Rectangle(36, 648, 200, 100);
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance
                .setReason(reason)
                .setLocation(location)
 
                // Specify if the appearance before field is signed will be used
                // as a background for the signed field. The "false" value is the default value.
                .setReuseAppearance(false)
                .setPageRect(rect)
                .setPageNumber(1);
        signer.setFieldName("sig");
 
        IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();
 
        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
    }
}
C4_02_SignWithPKCS11USB.java
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2020 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
/*
 * This class is part of the white paper entitled
 * "Digital Signatures for PDF documents"
 * written by Bruno Lowagie
 *
 * For more info, go to: http://itextpdf.com/learn
 */
package com.itextpdf.samples.signatures.chapter04;
 
import java.io.FileOutputStream;
import java.util.Collection;
import sun.security.pkcs11.SunPKCS11;
import sun.security.pkcs11.wrapper.CK_C_INITIALIZE_ARGS;
import sun.security.pkcs11.wrapper.CK_TOKEN_INFO;
import sun.security.pkcs11.wrapper.PKCS11;
import sun.security.pkcs11.wrapper.PKCS11Exception;
 
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.CertificateUtil;
import com.itextpdf.signatures.ICrlClient;
import com.itextpdf.signatures.CrlClientOnline;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.IOcspClient;
import com.itextpdf.signatures.OcspClientBouncyCastle;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.ITSAClient;
import com.itextpdf.signatures.PrivateKeySignature;
import com.itextpdf.signatures.TSAClientBouncyCastle;
 
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
 
import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
public class C4_02_SignWithPKCS11USB {
    public static final String DEST = "./target/signatures/chapter04/";
 
    public static final String SRC = "./src/test/resources/pdfs/hello.pdf";
 
    public static final String[] RESULT_FILES = new String[] {
            "hello_token.pdf"
    };
 
    public static void main(String[] args) throws IOException, GeneralSecurityException {
        File file = new File(DEST);
        file.mkdirs();
 
        Properties properties = new Properties();
 
        // Specify the correct path to the certificate
        properties.load(new FileInputStream("C:/signkey.properties"));
        char[] pass = properties.getProperty("PASSWORD").toCharArray();
 
        // Specify the correct path to the CRYPTOKI (PKCS#11) DLL.
        String dllPath = "c:/windows/system32/dkck201.dll";
        long[] slots = getSlotsWithTokens(dllPath);
        if (slots != null) {
            String config = "name=ikey4000\n" +
                    "library=" + dllPath + "\n" +
                    "slotListIndex = " + slots[0];
            ByteArrayInputStream bais = new ByteArrayInputStream(config.getBytes());
            Provider providerPKCS11 = new SunPKCS11(bais);
            Security.addProvider(providerPKCS11);
            BouncyCastleProvider providerBC = new BouncyCastleProvider();
            Security.addProvider(providerBC);
 
            KeyStore ks = KeyStore.getInstance("PKCS11");
            ks.load(null, pass);
            String alias = ks.aliases().nextElement();
            PrivateKey pk = (PrivateKey) ks.getKey(alias, pass);
            Certificate[] chain = ks.getCertificateChain(alias);
            IOcspClient ocspClient = new OcspClientBouncyCastle(null);
            ITSAClient tsaClient = null;
            for (int i = 0; i < chain.length; i++) {
                X509Certificate cert = (X509Certificate) chain[i];
                String tsaUrl = CertificateUtil.getTSAURL(cert);
                if (tsaUrl != null) {
                    tsaClient = new TSAClientBouncyCastle(tsaUrl);
                    break;
                }
            }
 
            List<ICrlClient> crlList = new ArrayList<ICrlClient>();
            crlList.add(new CrlClientOnline(chain));
 
            new C4_02_SignWithPKCS11USB().sign(SRC, DEST + RESULT_FILES[0], chain, pk,
                    DigestAlgorithms.SHA256, providerPKCS11.getName(), PdfSigner.CryptoStandard.CMS,
                    "Test", "Ghent", crlList, ocspClient, tsaClient, 0);
        } else {
            System.out.println("An exception was encountered while getting token slot's indexes.");
        }
    }
 
    public void sign(String src, String dest, Certificate[] chain, PrivateKey pk,
            String digestAlgorithm, String provider, PdfSigner.CryptoStandard subfilter,
            String reason, String location, Collection<ICrlClient> crlList,
            IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
 
        // Create the signature appearance
        Rectangle rect = new Rectangle(36, 648, 200, 100);
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance
                .setReason(reason)
                .setLocation(location)
 
                // Specify if the appearance before field is signed will be used
                // as a background for the signed field. The "false" value is the default value.
                .setReuseAppearance(false)
                .setPageRect(rect)
                .setPageNumber(1);
        signer.setFieldName("sig");
 
        IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();
 
        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
    }
 
    // Method returns a list of token slot's indexes
    public static long[] getSlotsWithTokens(String libraryPath) {
        CK_C_INITIALIZE_ARGS initArgs = new CK_C_INITIALIZE_ARGS();
        String functionList = "C_GetFunctionList";
 
        initArgs.flags = 0;
        PKCS11 tmpPKCS11 = null;
        long[] slotList = null;
        try {
            try {
                tmpPKCS11 = PKCS11.getInstance(libraryPath, functionList, initArgs, false);
            } catch (IOException ex) {
                ex.printStackTrace();
                return null;
            }
        } catch (PKCS11Exception e) {
            try {
                initArgs = null;
                tmpPKCS11 = PKCS11.getInstance(libraryPath, functionList, initArgs, true);
            } catch (IOException | PKCS11Exception ex) {
                ex.printStackTrace();
                return null;
            }
        }
 
        try {
            slotList = tmpPKCS11.C_GetSlotList(true);
 
            for (long slot : slotList) {
                CK_TOKEN_INFO tokenInfo = tmpPKCS11.C_GetTokenInfo(slot);
                System.out.println("slot: " + slot + "\nmanufacturerID: "
                        + String.valueOf(tokenInfo.manufacturerID) + "\nmodel: "
                        + String.valueOf(tokenInfo.model));
            }
        } catch (Throwable ex) {
            ex.printStackTrace();
            return null;
        }
 
        return slotList;
    }
}
C4_03_SignWithPKCS11SC.java
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2020 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
/*
 * This class is part of the white paper entitled
 * "Digital Signatures for PDF documents"
 * written by Bruno Lowagie
 *
 * For more info, go to: http://itextpdf.com/learn
 */
package com.itextpdf.samples.signatures.chapter04;
 
import java.io.File;
import java.io.FileOutputStream;
import java.util.Collection;
import sun.security.pkcs11.SunPKCS11;
 
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.ICrlClient;
import com.itextpdf.signatures.CrlClientOnline;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.IOcspClient;
import com.itextpdf.signatures.ITSAClient;
import com.itextpdf.signatures.OcspClientBouncyCastle;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
 
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
 
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.security.pkcs11.wrapper.CK_C_INITIALIZE_ARGS;
import sun.security.pkcs11.wrapper.CK_TOKEN_INFO;
import sun.security.pkcs11.wrapper.PKCS11;
import sun.security.pkcs11.wrapper.PKCS11Exception;
 
public class C4_03_SignWithPKCS11SC {
    public static final String DEST = "./target/signatures/chapter04/";
 
    public static final String SRC = "./src/test/resources/pdfs/hello.pdf";
 
    public static final String[] RESULT_FILES = new String[] {
            "hello_smartcard_Authentication.pdf",
            "hello_smartcard_Signature.pdf"
    };
 
    public static void main(String[] args) throws IOException, GeneralSecurityException {
        File file = new File(DEST);
        file.mkdirs();
 
        // Specify the correct path to the DLL.
        String dllPath = "c:/windows/system32/beidpkcs11.dll";
        long[] slots = getSlotsWithTokens(dllPath);
        if (slots != null) {
            String config = "name=beid\n" +
                    "library=" + dllPath + "\n" +
                    "slotListIndex = " + slots[0];
            ByteArrayInputStream bais = new ByteArrayInputStream(config.getBytes());
            Provider providerPKCS11 = new SunPKCS11(bais);
            Security.addProvider(providerPKCS11);
            BouncyCastleProvider providerBC = new BouncyCastleProvider();
            Security.addProvider(providerBC);
            KeyStore ks = KeyStore.getInstance("PKCS11");
 
            /* All the signing operations are passed to the BeId API.
             * That is why the stream and password are null.
             */
            ks.load(null, null);
            Enumeration<String> aliases = ks.aliases();
            while (aliases.hasMoreElements()) {
                System.out.println(aliases.nextElement());
            }
 
            smartCardSign(providerPKCS11.getName(), ks, "Authentication", DEST + RESULT_FILES[0]);
            smartCardSign(providerPKCS11.getName(), ks, "Signature", DEST + RESULT_FILES[1]);
        } else {
            System.out.println("An exception was encountered while getting token slot's indexes.");
        }
    }
 
    public static void smartCardSign(String provider, KeyStore ks, String alias, String dest)
            throws GeneralSecurityException, IOException {
        PrivateKey pk = (PrivateKey) ks.getKey(alias, null);
        Certificate[] chain = ks.getCertificateChain(alias);
        IOcspClient ocspClient = new OcspClientBouncyCastle(null);
        List<ICrlClient> crlList = new ArrayList<ICrlClient>();
        crlList.add(new CrlClientOnline(chain));
 
        new C4_03_SignWithPKCS11SC().sign(SRC, dest, chain, pk, DigestAlgorithms.SHA256, provider,
                PdfSigner.CryptoStandard.CMS, "Test", "Ghent",
                crlList, ocspClient, null, 0);
    }
 
    public void sign(String src, String dest, Certificate[] chain, PrivateKey pk,
            String digestAlgorithm, String provider, PdfSigner.CryptoStandard subfilter,
            String reason, String location, Collection<ICrlClient> crlList,
            IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize)
            throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
 
        // Create the signature appearance
        Rectangle rect = new Rectangle(36, 648, 200, 100);
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance
                .setReason(reason)
                .setLocation(location)
 
                // Specify if the appearance before field is signed will be used
                // as a background for the signed field. The "false" value is the default value.
                .setReuseAppearance(false)
                .setPageRect(rect)
                .setPageNumber(1);
        signer.setFieldName("sig");
 
        IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        IExternalDigest digest = new BouncyCastleDigest();
 
        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
    }
 
    // Method returns a list of token slot's indexes
    public static long[] getSlotsWithTokens(String libraryPath) {
        CK_C_INITIALIZE_ARGS initArgs = new CK_C_INITIALIZE_ARGS();
        String functionList = "C_GetFunctionList";
 
        initArgs.flags = 0;
        PKCS11 tmpPKCS11 = null;
        long[] slotList = null;
        try {
            try {
                tmpPKCS11 = PKCS11.getInstance(libraryPath, functionList, initArgs, false);
            } catch (IOException ex) {
                ex.printStackTrace();
                return null;
            }
        } catch (PKCS11Exception e) {
            try {
                initArgs = null;
                tmpPKCS11 = PKCS11.getInstance(libraryPath, functionList, initArgs, true);
            } catch (IOException | PKCS11Exception ex) {
                ex.printStackTrace();
                return null;
            }
        }
 
        try {
            slotList = tmpPKCS11.C_GetSlotList(true);
 
            for (long slot : slotList) {
                CK_TOKEN_INFO tokenInfo = tmpPKCS11.C_GetTokenInfo(slot);
                System.out.println("slot: " + slot + "\nmanufacturerID: "
                        + String.valueOf(tokenInfo.manufacturerID) + "\nmodel: "
                        + String.valueOf(tokenInfo.model));
            }
        } catch (Throwable ex) {
            ex.printStackTrace();
            return null;
        }
 
        return slotList;
    }
}
C4_07_ClientServerSigning.java
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
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2020 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
/*
 * This class is part of the white paper entitled
 * "Digital Signatures for PDF documents"
 * written by Bruno Lowagie
 *
 * For more info, go to: http://itextpdf.com/learn
 */
package com.itextpdf.samples.signatures.chapter04;
 
import com.itextpdf.kernel.PdfException;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
 
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.InputStream;
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
 
public class C4_07_ClientServerSigning {
    public static final String DEST = "./target/signatures/chapter04/";
 
    public static final String SRC = "./src/test/resources/pdfs/hello.pdf";
    public static final String CERT = "https://demo.itextsupport.com/SigningApp/itextpdf.cer";
 
    public static final String[] RESULT_FILES = new String[] {
            "hello_server.pdf"
    };
 
    public static void main(String[] args) throws GeneralSecurityException, IOException {
        File file = new File(DEST);
        file.mkdirs();
 
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        URL certUrl = new URL(CERT);
        Certificate[] chain = new Certificate[1];
        try (InputStream stream = certUrl.openStream()) {
            chain[0] = factory.generateCertificate(stream);
        }
 
        new C4_07_ClientServerSigning().sign(SRC, DEST + RESULT_FILES[0], chain, PdfSigner.CryptoStandard.CMS,
                "Test", "Ghent");
    }
 
    public void sign(String src, String dest, Certificate[] chain, PdfSigner.CryptoStandard subfilter,
            String reason, String location) throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
 
        // Create the signature appearance
        Rectangle rect = new Rectangle(36, 648, 200, 100);
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance
                .setReason(reason)
                .setLocation(location)
                .setPageRect(rect)
                .setPageNumber(1);
        signer.setFieldName("sig");
 
        IExternalDigest digest = new BouncyCastleDigest();
        IExternalSignature signature = new ServerSignature();
 
        // Sign the document using the detached mode, CMS or CAdES equivalent.
        signer.signDetached(digest, signature, chain, null, null, null,
                0, subfilter);
    }
 
    public class ServerSignature implements IExternalSignature {
        public static final String SIGN = "http://demo.itextsupport.com/SigningApp/signbytes";
 
        public String getHashAlgorithm() {
            return DigestAlgorithms.SHA256;
        }
 
        public String getEncryptionAlgorithm() {
            return "RSA";
        }
 
        public byte[] sign(byte[] message) throws GeneralSecurityException {
            try {
                URL url = new URL(SIGN);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setDoOutput(true);
                conn.setRequestMethod("POST");
                conn.connect();
 
                OutputStream os = conn.getOutputStream();
                os.write(message);
                os.flush();
                os.close();
 
                InputStream is = conn.getInputStream();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] b = new byte[32];
                int read;
                while ((read = is.read(b)) != -1) {
                    baos.write(b, 0, read);
                }
 
                is.close();
 
                return baos.toByteArray();
            } catch (IOException e) {
                throw new PdfException(e);
            }
        }
    }
}
C4_08_ServerClientSigning.java
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
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2020 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
/*
 * This class is part of the white paper entitled
 * "Digital Signatures for PDF documents"
 * written by Bruno Lowagie
 *
 * For more info, go to: http://itextpdf.com/learn
 */
package com.itextpdf.samples.signatures.chapter04;
 
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Signature;
 
import java.util.List;
 
public class C4_08_ServerClientSigning {
    public static final String DEST = "./target/signatures/chapter04/";
 
    public static final String KEYSTORE = "./src/test/resources/encryption/ks";
    public static final String CERT = "./src/test/resources/encryption/bruno.crt";
    public static final String PRE = "http://demo.itextsupport.com/SigningApp/presign";
    public static final String POST = "http://demo.itextsupport.com/SigningApp/postsign";
 
    public static final String[] RESULT_FILES = new String[] {
            "hello_server2.pdf"
    };
 
    public static final char[] PASSWORD = "password".toCharArray();
 
    public static void main(String[] args) throws IOException, GeneralSecurityException {
        File file = new File(DEST);
        file.mkdirs();
 
        // Make a connection to a PreSign servlet to ask to create a document,
        // then calculate its hash and send it to us
        URL url = new URL(PRE);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        conn.connect();
 
        // Upload your self-signed certificate
        OutputStream os = conn.getOutputStream();
        FileInputStream fis = new FileInputStream(CERT);
        int read;
        byte[] data = new byte[256];
        while ((read = fis.read(data, 0, data.length)) != -1) {
            os.write(data, 0, read);
        }
 
        os.flush();
        os.close();
 
        // Use cookies to maintain a session
        List<String> cookies = conn.getHeaderFields().get("Set-Cookie");
 
        // Receive a hash that needs to be signed
        InputStream is = conn.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        data = new byte[256];
        while ((read = is.read(data)) != -1) {
            baos.write(data, 0, read);
        }
 
        is.close();
        byte[] hash = baos.toByteArray();
 
        // Load your private key from the key store
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
 
        // Sign the hash received from the server
        Signature sig = Signature.getInstance("SHA256withRSA");
        sig.initSign(pk);
        sig.update(hash);
        data = sig.sign();
 
        // Make a connection to the PostSign Servlet to send the signed bytes to the server.
        url = new URL(POST);
        conn = (HttpURLConnection) url.openConnection();
        for (String cookie : cookies) {
            conn.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
        }
 
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        conn.connect();
 
        //Upload the signed bytes
        os = conn.getOutputStream();
        os.write(data);
        os.flush();
        os.close();
 
        // Receive the signed document
        is = conn.getInputStream();
        FileOutputStream fos = new FileOutputStream(DEST + RESULT_FILES[0]);
        data = new byte[256];
        while ((read = is.read(data)) != -1) {
            fos.write(data, 0, read);
        }
 
        is.close();
        fos.flush();
        fos.close();
    }
}
C4_09_DeferredSigning.java
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
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2020 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
package com.itextpdf.samples.signatures.chapter04;
 
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDictionary;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
 
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.ExternalBlankSignatureContainer;
import com.itextpdf.signatures.IExternalSignatureContainer;
import com.itextpdf.signatures.PdfPKCS7;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
 
import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
public class C4_09_DeferredSigning {
    public static final String DEST = "./target/signatures/chapter04/";
 
    public static final String SRC = "./src/test/resources/pdfs/hello.pdf";
    public static final String TEMP = "./target/signatures/chapter04/hello_empty_sig.pdf";
    public static final String KEYSTORE = "./src/test/resources/encryption/ks";
 
    public static final char[] PASSWORD = "password".toCharArray();
 
    public static final String[] RESULT_FILES = new String[] {
            "hello_sig_ok.pdf"
    };
 
    public static void main(String[] args) throws IOException, GeneralSecurityException {
        File file = new File(DEST);
        file.mkdirs();
 
        BouncyCastleProvider providerBC = new BouncyCastleProvider();
        Security.addProvider(providerBC);
 
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = ks.aliases().nextElement();
        Certificate[] chain = ks.getCertificateChain(alias);
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
 
        C4_09_DeferredSigning app = new C4_09_DeferredSigning();
        app.emptySignature(SRC, TEMP, "sig", chain);
        app.createSignature(TEMP, DEST + RESULT_FILES[0], "sig", pk, chain);
    }
 
    public void emptySignature(String src, String dest, String fieldname, Certificate[] chain)
            throws IOException, GeneralSecurityException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance
                .setPageRect(new Rectangle(36, 748, 200, 100))
                .setPageNumber(1)
                .setCertificate(chain[0]);
        signer.setFieldName(fieldname);
 
        /* ExternalBlankSignatureContainer constructor will create the PdfDictionary for the signature
         * information and will insert the /Filter and /SubFilter values into this dictionary.
         * It will leave just a blank placeholder for the signature that is to be inserted later.
         */
        IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.Adobe_PPKLite,
                PdfName.Adbe_pkcs7_detached);
 
        // Sign the document using an external container.
        // 8192 is the size of the empty signature placeholder.
        signer.signExternalContainer(external, 8192);
    }
 
    public void createSignature(String src, String dest, String fieldName, PrivateKey pk, Certificate[] chain)
            throws IOException, GeneralSecurityException {
        PdfReader reader = new PdfReader(src);
        try(FileOutputStream os = new FileOutputStream(dest)) {
            PdfSigner signer = new PdfSigner(reader, os, new StampingProperties());
 
            IExternalSignatureContainer external = new MyExternalSignatureContainer(pk, chain);
 
            // Signs a PDF where space was already reserved. The field must cover the whole document.
            signer.signDeferred(signer.getDocument(), fieldName, os, external);
        }
    }
 
    class MyExternalSignatureContainer implements IExternalSignatureContainer {
 
        protected PrivateKey pk;
        protected Certificate[] chain;
 
        public MyExternalSignatureContainer(PrivateKey pk, Certificate[] chain) {
            this.pk = pk;
            this.chain = chain;
        }
 
        public byte[] sign(InputStream is) throws GeneralSecurityException {
            try {
                PrivateKeySignature signature = new PrivateKeySignature(pk, "SHA256", "BC");
                String hashAlgorithm = signature.getHashAlgorithm();
                BouncyCastleDigest digest = new BouncyCastleDigest();
 
                PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, null, digest, false);
                byte hash[] = DigestAlgorithms.digest(is, digest.getMessageDigest(hashAlgorithm));
                byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, PdfSigner.CryptoStandard.CMS, null, null);
                byte[] extSignature = signature.sign(sh);
                sgn.setExternalDigest(extSignature, null, signature.getEncryptionAlgorithm());
 
                return sgn.getEncodedPKCS7(hash, PdfSigner.CryptoStandard.CMS, null, null, null);
            } catch (IOException ioe) {
                throw new RuntimeException(ioe);
            }
        }
 
        public void modifySigningDictionary(PdfDictionary signDic) {
        }
    }
}
C4_07_ClientServerSigning.cs
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
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2020 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
/*
 * This class is part of the white paper entitled
 * "Digital Signatures for PDF documents"
 * written by Bruno Lowagie
 *
 * For more info, go to: http://itextpdf.com/learn
 */
 
using System;
using System.IO;
using System.Net;
using iText.Kernel;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.X509;
 
namespace iText.Samples.Signatures.Chapter04
{
    public class C4_07_ClientServerSigning
    {
        public static readonly string DEST = "results/signatures/chapter04/";
 
        public static readonly string SRC = "../../resources/pdfs/hello.pdf";
        public static readonly string CERT = "https://demo.itextsupport.com/SigningApp/itextpdf.cer";
 
        public static readonly String[] RESULT_FILES =
        {
            "hello_server.pdf"
        };
 
        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();
 
            Uri certUrl = new Uri(CERT);
            HttpWebRequest request = (HttpWebRequest) WebRequest.Create(certUrl);
            request.Method = WebRequestMethods.Http.Get;
            HttpWebResponse response = (HttpWebResponse) request.GetResponse();
            X509CertificateParser parser = new X509CertificateParser();
            X509Certificate[] chain = new X509Certificate[1];
            using (Stream stream = response.GetResponseStream())
            {
                chain[0] = parser.ReadCertificate(stream);
            }
 
            new C4_07_ClientServerSigning().Sign(SRC, DEST + RESULT_FILES[0], chain, PdfSigner.CryptoStandard.CMS,
                "Test", "Ghent");
        }
 
        public void Sign(String src, String dest, X509Certificate[] chain, PdfSigner.CryptoStandard subfilter,
            String reason, String location)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());
 
            // Create the signature appearance
            Rectangle rect = new Rectangle(36, 648, 200, 100);
            PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
            appearance
                .SetReason(reason)
                .SetLocation(location)
                .SetPageRect(rect)
                .SetPageNumber(1);
            signer.SetFieldName("sig");
 
            IExternalSignature pks = new ServerSignature();
 
            // Sign the document using the detached mode, CMS or CAdES equivalent.
            signer.SignDetached(pks, chain, null, null, null, 0, subfilter);
        }
 
        public class ServerSignature : IExternalSignature
        {
            public static readonly String SIGN = "http://demo.itextsupport.com/SigningApp/signbytes";
 
            public String GetHashAlgorithm()
            {
                return DigestAlgorithms.SHA256;
            }
 
            public String GetEncryptionAlgorithm()
            {
                return "RSA";
            }
 
            public byte[] Sign(byte[] message)
            {
                try
                {
                    Uri url = new Uri(SIGN);
                    var httpWebRequest = (HttpWebRequest) WebRequest.Create(url);
                    httpWebRequest.Method = "POST";
 
                    using (Stream stream = httpWebRequest.GetRequestStream())
                    {
                        stream.Write(message, 0, message.Length);
                    }
 
                    var httpResponse = (HttpWebResponse) httpWebRequest.GetResponse();
                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        Stream stream = httpResponse.GetResponseStream();
                        stream.CopyTo(memoryStream);
                        stream.Close();
                        
                        return memoryStream.ToArray();
                    }
                }
                catch (IOException e)
                {
                    throw new PdfException(e);
                }
            }
        }
    }
}
C4_08_ServerClientSigning.cs
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
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2020 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
/*
 * This class is part of the white paper entitled
 * "Digital Signatures for PDF documents"
 * written by Bruno Lowagie
 *
 * For more info, go to: http://itextpdf.com/learn
 */
 
using System;
using System.IO;
using System.Net;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
 
namespace iText.Samples.Signatures.Chapter04
{
    public class C4_08_ServerClientSigning
    {
        public static readonly String DEST = "results/signatures/chapter04/";
 
        public static readonly String KEYSTORE = "../../resources/encryption/ks";
        public static readonly String CERT = "../../resources/encryption/bruno.crt";
        public static readonly String PRE = "http://demo.itextsupport.com/SigningApp/presign";
        public static readonly String POST = "http://demo.itextsupport.com/SigningApp/postsign";
 
        public static readonly String[] RESULT_FILES = new String[]
        {
            "hello_server2.pdf"
        };
 
        public static readonly char[] PASSWORD = "password".ToCharArray();
 
        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();
 
            // Make a connection to a PreSign servlet to ask to create a document,
            // then calculate its hash and send it to us
            HttpWebRequest request = (HttpWebRequest) WebRequest.Create(PRE);
            request.Method = "POST";
 
            // Upload our self-signed certificate
            Stream os = request.GetRequestStream();
            byte[] data = new byte[256];
            int read;
            using (FileStream fis = new FileStream(CERT, FileMode.Open))
            {
                while ((read = fis.Read(data, 0, data.Length)) != 0)
                {
                    os.Write(data, 0, read);
                }
            }
 
            os.Flush();
            os.Close();
 
            HttpWebResponse response = (HttpWebResponse) request.GetResponse();
 
            // Use cookies to maintain a session
            String cookies = response.Headers["Set-Cookie"];
 
            // Receive a hash that needs to be signed
            Stream istream = response.GetResponseStream();
            MemoryStream memoryStream = new MemoryStream();
            istream.CopyTo(memoryStream);
            istream.Close();
            byte[] hash = memoryStream.ToArray();
 
            // Load our private key from the key store
            Pkcs12Store store = new Pkcs12Store(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
 
            // Searching for private key
            String alias = null;
            foreach (string al in store.Aliases)
            {
                if (store.IsKeyEntry(al) && store.GetKey(al).Key.IsPrivate)
                {
                    alias = al;
                    break;
                }
            }
 
            AsymmetricKeyEntry pk = store.GetKey(alias);
 
            // Sign the hash received from the server
            ISigner sig = SignerUtilities.GetSigner("SHA256withRSA");
            sig.Init(true, pk.Key);
            sig.BlockUpdate(hash, 0, hash.Length);
            data = sig.GenerateSignature();
 
            // Make a connection to the PostSign Servlet
            request = (HttpWebRequest) WebRequest.Create(POST);
            request.Headers.Add(HttpRequestHeader.Cookie, cookies.Split(";".ToCharArray(), 2)[0]);
            request.Method = "POST";
 
            // Upload the signed bytes
            os = request.GetRequestStream();
            os.Write(data, 0, data.Length);
            os.Flush();
            os.Close();
 
            // Receive the signed document
            response = (HttpWebResponse) request.GetResponse();
            istream = response.GetResponseStream();
            using (FileStream fos = new FileStream(DEST + RESULT_FILES[0], FileMode.Create))
            {
                data = new byte[256];
                while ((read = istream.Read(data, 0, data.Length)) != 0)
                {
                    fos.Write(data, 0, read);
                }
 
                istream.Close();
            }
        }
    }
}
C4_09_DeferredSigning.cs
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
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2020 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
/*
 * This class is part of the white paper entitled
 * "Digital Signatures for PDF documents"
 * written by Bruno Lowagie
 *
 * For more info, go to: http://itextpdf.com/learn
 */
 
using System;
using System.IO;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.X509;
 
namespace iText.Samples.Signatures.Chapter04
{
    public class C4_09_DeferredSigning
    {
        public static readonly String DEST = "results/signatures/chapter04/";
 
        public static readonly String SRC = "../../resources/pdfs/hello.pdf";
        public static readonly String TEMP = "results/signatures/chapter04/hello_empty_sig.pdf";
        public static readonly String KEYSTORE = "../../resources/encryption/ks";
 
        public static readonly char[] PASSWORD = "password".ToCharArray();
 
        public static readonly String[] RESULT_FILES = new String[]
        {
            "hello_sig_ok.pdf"
        };
 
        public static void Main(String[] args)
        {
            DirectoryInfo directory = new DirectoryInfo(DEST);
            directory.Create();
            Pkcs12Store pk12 = new Pkcs12Store(new FileStream(KEYSTORE, FileMode.Open, FileAccess.Read), PASSWORD);
            string alias = null;
            foreach (var a in pk12.Aliases)
            {
                alias = ((string) a);
                if (pk12.IsKeyEntry(alias))
                    break;
            }
 
            ICipherParameters pk = pk12.GetKey(alias).Key;
            X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
            X509Certificate[] chain = new X509Certificate[ce.Length];
            for (int k = 0; k < ce.Length; ++k)
            {
                chain[k] = ce[k].Certificate;
            }
 
            C4_09_DeferredSigning app = new C4_09_DeferredSigning();
            app.EmptySignature(SRC, TEMP, "sig", chain);
            app.CreateSignature(TEMP, DEST + RESULT_FILES[0], "sig", pk, chain);
        }
 
        public void EmptySignature(String src, String dest, String fieldname, X509Certificate[] chain)
        {
            PdfReader reader = new PdfReader(src);
            PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), new StampingProperties());
 
            PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
            appearance
                .SetPageRect(new Rectangle(36, 748, 200, 100))
                .SetPageNumber(1)
                .SetCertificate(chain[0]);
            signer.SetFieldName(fieldname);
 
            /* ExternalBlankSignatureContainer constructor will create the PdfDictionary for the signature
             * information and will insert the /Filter and /SubFilter values into this dictionary.
             * It will leave just a blank placeholder for the signature that is to be inserted later.
             */
            IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.Adobe_PPKLite,
                PdfName.Adbe_pkcs7_detached);
 
            // Sign the document using an external container
            // 8192 is the size of the empty signature placeholder.
            signer.SignExternalContainer(external, 8192);
        }
 
        public void CreateSignature(String src, String dest, String fieldName,
            ICipherParameters pk, X509Certificate[] chain)
        {
            PdfReader reader = new PdfReader(src);
            using (FileStream os = new FileStream(dest, FileMode.Create))
            {
                PdfSigner signer = new PdfSigner(reader, os, new StampingProperties());
 
                IExternalSignatureContainer external = new MyExternalSignatureContainer(pk, chain);
 
                // Signs a PDF where space was already reserved. The field must cover the whole document.
                PdfSigner.SignDeferred(signer.GetDocument(), fieldName, os, external);
            }
        }
 
        class MyExternalSignatureContainer : IExternalSignatureContainer
        {
            protected ICipherParameters pk;
            protected X509Certificate[] chain;
 
            public MyExternalSignatureContainer(ICipherParameters pk, X509Certificate[] chain)
            {
                this.pk = pk;
                this.chain = chain;
            }
 
            public byte[] Sign(Stream inputStream)
            {
                try
                {
                    PrivateKeySignature signature = new PrivateKeySignature(pk, "SHA256");
                    String hashAlgorithm = signature.GetHashAlgorithm();
 
                    PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, false);
                    byte[] hash = DigestAlgorithms.Digest(inputStream, hashAlgorithm);
                    byte[] sh = sgn.GetAuthenticatedAttributeBytes(hash, PdfSigner.CryptoStandard.CMS,
                        null, null);
                    byte[] extSignature = signature.Sign(sh);
                    sgn.SetExternalDigest(extSignature, null, signature.GetEncryptionAlgorithm());
 
                    return sgn.GetEncodedPKCS7(hash, PdfSigner.CryptoStandard.CMS, null,
                        null, null);
                }
                catch (IOException ioe)
                {
                    throw new Exception(ioe.Message);
                }
            }
 
            public void ModifySigningDictionary(PdfDictionary signDic)
            {
            }
        }
    }
}

Click the following link to see the legacy example for iText 5. Except for security fixes, iText 5 is no longer being developed.



Contact

Still have questions? 

We're happy to answer your questions. Reach out to us and we'll get back to you shortly.

Contact us
Stay updated

Join 11,000+ subscribers and become an iText PDF expert by staying up to date with our new products, updates, tips, technical solutions and happenings.

Subscribe Now