sign (
sign.cpp) –
this example shows how to prepare a signature field, digitally sign an existing
PDF document and finally sign the prepared signature field, using the internal
litePDF signing API, which allows PFX and PEM certificates to be used.
The example also uses two signers for one signature field, but the Adobe
Reader 11 shows only the first signer certificate, not both of them.
1 /*
2 * (c) 2013-2016 http://www.litePDF.cz
3 * (c) 2017 zyx [@:] zyx gmx [dot] us
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any damages
7 * arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software
15 * in a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 * 2. Altered source versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software.
19 * 3. This notice may not be removed or altered from any source distribution.
20 */
21
22 #include <windows.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <string>
26 #include <time.h>
27
28 #include "share/litePDF.h"
29
30 static void drawText(HDC hDC,
31 const char *msg,
32 int px,
33 int py,
34 int fontHeight,
35 COLORREF color)
36 {
37 LOGFONTA lf = {0, };
38 lf.lfHeight = fontHeight;
39 strcpy(lf.lfFaceName, "Helvetica");
40
41 HFONT fnt;
42 HGDIOBJ oldFnt;
43
44 fnt = CreateFontIndirect(&lf);
45 oldFnt = SelectObject(hDC, fnt);
46
47 SetTextColor(hDC, color);
48 TextOut(hDC, px, py, msg, strlen(msg));
49
50 SelectObject(hDC, oldFnt);
51 DeleteObject(fnt);
52 }
53
54 static void addPage(litePDF::TLitePDF &litePDF,
55 unsigned int pageWidth,
56 unsigned int pageHeight,
57 const char *msg)
58 {
59 HDC hDC;
60
61 // add a new page, with large-enough pixel scale
62 hDC = litePDF.AddPage(litePDF.MMToUnit(pageWidth), litePDF.MMToUnit(pageHeight),
63 pageWidth * 10, pageHeight * 10,
64 LitePDFDrawFlag_SubstituteFonts);
65
66 // draw the text, with ~5mm font height
67 drawText(hDC, msg, 100, 100, -50, RGB(0, 0, 0));
68
69 // finish drawing
70 litePDF.FinishPage(hDC);
71 }
72
73 static unsigned int createResource(litePDF::TLitePDF &litePDF,
74 COLORREF color,
75 const char *text)
76 {
77 HDC hDC;
78 int w = 50, h = 10;
79
80 // create a new resource
81 hDC = litePDF.AddResource(litePDF.MMToUnit(w), litePDF.MMToUnit(h), w * 10, h * 10, LitePDFDrawFlag_SubstituteFonts);
82
83 LOGBRUSH brush;
84 brush.lbColor = color;
85 brush.lbHatch = 0;
86 brush.lbStyle = BS_SOLID;
87
88 HPEN pen = ExtCreatePen(PS_GEOMETRIC | PS_DOT | PS_ENDCAP_FLAT | PS_JOIN_BEVEL, 10, &brush, 0, NULL);
89 HGDIOBJ prevPen = SelectObject(hDC, pen);
90
91 // rectangle on boundaries
92 MoveToEx(hDC, 0, 0, NULL);
93 LineTo(hDC, w * 10, 0);
94 LineTo(hDC, w * 10, h * 10);
95 LineTo(hDC, 0, h * 10);
96 LineTo(hDC, 0, 0);
97
98 SelectObject(hDC, prevPen);
99 DeleteObject(pen);
100
101 // draw the text
102 drawText(hDC, text, 20, 20, -50, color);
103
104 // finish drawing
105 return litePDF.FinishResource(hDC);
106 }
107
108 static BYTE *getFileAsData(const char *fileName, unsigned int *dataLength)
109 {
110 FILE *f = fopen(fileName, "rb");
111 if (!f) {
112 std::string msg = "Failed to open " + std::string(fileName);
113 throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
114 }
115
116 if (fseek(f, 0, SEEK_END) != 0) {
117 fclose(f);
118 throw TLitePDFException(ERROR_CANNOT_MAKE,
119 "Failed to move to the end of the file");
120 }
121
122 *dataLength = ftell(f);
123
124 if (fseek(f, 0, SEEK_SET) != 0) {
125 fclose(f);
126 throw TLitePDFException(ERROR_CANNOT_MAKE,
127 "Failed to move to the beginning of the file");
128 }
129
130 BYTE *data = (BYTE *) malloc(sizeof(BYTE) * (*dataLength));
131 if (!data) {
132 fclose(f);
133 throw TLitePDFException(ERROR_OUTOFMEMORY, "Out of memory");
134 }
135
136 if (fread(data, sizeof(BYTE), *dataLength, f) != *dataLength) {
137 fclose(f);
138 free(data);
139 throw TLitePDFException(ERROR_CANNOT_MAKE, "Failed to read whole file");
140 }
141
142 fclose(f);
143 return data;
144 }
145
146 int main(void)
147 {
148 int res = 0;
149 BYTE *cert = NULL, *pkey = NULL;
150 unsigned int certLen = 0, pkeyLen = 0;
151
152 using namespace litePDF;
153
154 try {
155 TLitePDF litePDF;
156 unsigned int signatureIndex, ii;
157
158 // create a document
159 litePDF.CreateMemDocument();
160
161 // create some pages
162 addPage(litePDF, 210, 297, "To be digitally signed document");
163 addPage(litePDF, 210, 297, "Page 2");
164
165 // add an unsigned signature field, to be signed by Alice & Bob later;
166 // do not set other than appearances, otherwise Acrobat claims issues
167 signatureIndex = litePDF.CreateSignature("AliceAndBobSig",
168 0, // page index
169 10, 110, 50, 10, // position and size
170 LitePDFAnnotationFlag_None);
171
172 // create signature apperances
173 litePDF.SetSignatureAppearance(signatureIndex,
174 LitePDFAppearance_Normal,
175 createResource(litePDF, RGB(0, 0, 255), "Alice and Bob"),
176 0, 0);
177
178 litePDF.SetSignatureAppearance(signatureIndex,
179 LitePDFAppearance_Rollover,
180 createResource(litePDF, RGB(0, 255, 0), "Alice and Bob"),
181 0, 0);
182
183 litePDF.SetSignatureAppearance(signatureIndex,
184 LitePDFAppearance_Down,
185 createResource(litePDF, RGB(255, 0, 0), "Alice and Bob"),
186 0, 0);
187
188 // save a file with an unsigned signature
189 litePDF.SaveToFile("sign-1.pdf");
190
191 // close the document
192 litePDF.Close();
193
194 //-----------------------------------------------------------------
195
196 // load the saved document for incremental update
197 litePDF.LoadFromFile("sign-1.pdf", NULL, false, true);
198
199 // add a new signature, to be signed now
200 signatureIndex = litePDF.CreateSignature("CharlieSig",
201 0, // page index
202 90, 110, 50, 10, // position and size
203 LitePDFAnnotationFlag_None);
204
205 // create signature apperance
206 litePDF.SetSignatureAppearance(signatureIndex,
207 LitePDFAppearance_Normal,
208 createResource(litePDF, RGB(0, 0, 0), "Charlie"),
209 0, 0);
210
211 // set signature properties
212 litePDF.SetSignatureDate(signatureIndex, 0); // '0' means now
213 litePDF.SetSignatureReason(signatureIndex, L"Charlie agrees");
214 litePDF.SetSignatureLocation(signatureIndex, L"Workplace A");
215
216 // read Charlie's PEM certificate and private key
217 cert = getFileAsData("charlie.pem", &certLen);
218 pkey = getFileAsData("charlie.key", &pkeyLen);
219
220 // add Charlie as the signer (no password used for the private key)
221 litePDF.AddSignerPEM(cert, certLen, pkey, pkeyLen, NULL);
222
223 free(cert); cert = NULL;
224 free(pkey); pkey = NULL;
225
226 // sign with Charlie
227 litePDF.SaveToFileWithSign("sign-2.pdf", signatureIndex);
228
229 // close the document
230 litePDF.Close();
231
232 //-----------------------------------------------------------------
233
234 // load the saved document for incremental update
235 litePDF.LoadFromFile("sign-2.pdf", NULL, false, true);
236
237 // find the 'AliceAndBobSig', which had been created above
238 signatureIndex = ~0;
239
240 for (ii = 0; ii < litePDF.GetSignatureCount(); ii++) {
241 std::string name = litePDF.GetSignatureName(ii);
242 if (name == "AliceAndBobSig") {
243 signatureIndex = ii;
244 break;
245 }
246 }
247
248 if (signatureIndex == (unsigned int) ~0) {
249 throw TLitePDFException(ERROR_CANNOT_MAKE, "Failed to find 'AliceAndBobSig' signature field");
250 }
251
252 // make sure the signing date is correct
253 litePDF.SetSignatureDate(signatureIndex, 0); // '0' means now
254 litePDF.SetSignatureReason(signatureIndex, L"Alice and Bob agree too");
255 litePDF.SetSignatureLocation(signatureIndex, L"Meeting Room");
256
257 // add Alice as the first signers; with password "alice"
258 cert = getFileAsData("alice.pfx", &certLen);
259 litePDF.AddSignerPFX(cert, certLen, "alice");
260 free(cert); cert = NULL;
261
262 // add bob as the second signers; no password used
263 cert = getFileAsData("bob.pem", &certLen);
264 pkey = getFileAsData("bob.key", &pkeyLen);
265 litePDF.AddSignerPEM(cert, certLen, pkey, pkeyLen, NULL);
266 free(cert); cert = NULL;
267 free(pkey); pkey = NULL;
268
269 // sign with Alice and Bob to the previously created signature
270 litePDF.SaveToFileWithSign("sign-3.pdf", signatureIndex);
271
272 // close the document
273 litePDF.Close();
274
275 //-----------------------------------------------------------------
276 } catch (TLitePDFException &ex) {
277 fprintf(stderr, "litePDF Exception: %x: %s\n", ex.getCode(), ex.getMessage());
278 res = 1;
279 }
280
281 if (cert) {
282 free(cert);
283 }
284
285 if (pkey) {
286 free(pkey);
287 }
288
289 return res;
290 }