signmanual (
signmanual.cpp) –
this example shows how to digitally sign a PDF document, using Crypto API with
a certificate stored in a .pfx file. The first part defines a simple signer class,
MPdfSigner, which is responsible for signature operations and calls to Crypto API.
The main part of the example creates a new document and signs it with help of
the MPdfSigner, both to a file and to a memory buffer. The example shows how to
add a visual annotation with an information about the signature on the second page
of the document. It also signs already signed document, using the incremental
update. Note that a page changes invalidate any previous signatures.
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 <wincrypt.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <string>
27 #include <time.h>
28
29 #include "share/litePDF.h"
30
31 // Link with the crypt32.lib file
32 #pragma comment (lib, "crypt32.lib")
33
34 static std::string to_string(unsigned int num)
35 {
36 char buff[128];
37
38 if (num == (unsigned int) -1) {
39 return std::string("-1");
40 }
41
42 sprintf(buff, "%u", num);
43
44 return std::string(buff);
45 }
46
47 class MPdfSigner
48 {
49 private:
50 unsigned int lastSignatureIndex;
51
52 static void __stdcall appendSignatureData(const char *bytes,
53 unsigned int bytes_len,
54 void *user_data)
55 {
56 MPdfSigner *signer = (MPdfSigner *) user_data;
57
58 if (bytes && bytes_len) {
59 signer->AddData(bytes, bytes_len);
60 }
61 }
62
63 static void __stdcall finishSignature(char *signature,
64 unsigned int *signature_len,
65 void *user_data)
66 {
67 MPdfSigner *signer = (MPdfSigner *) user_data;
68 signer->Finish(signature, signature_len);
69 }
70
71 void loadCertificateStore(HANDLE *hStore)
72 {
73 BYTE *certBytes = NULL;
74 unsigned int certBytesLength = 0;
75
76 FILE *certFile = fopen("cert.pfx", "rb");
77 if (!certFile) {
78 throw TLitePDFException(ERROR_FILE_NOT_FOUND,
79 "Failed to open 'cert.pfx'");
80 }
81
82 fseek(certFile, 0, SEEK_END);
83 certBytesLength = ftell(certFile);
84 fseek(certFile, 0, SEEK_SET);
85 certBytes = (BYTE *) malloc(sizeof(BYTE) * certBytesLength);
86 if (!certBytes) {
87 throw TLitePDFException(ERROR_OUTOFMEMORY,
88 "Failed to allocate memory for cert.pfx");
89 }
90
91 fread(certBytes, sizeof(BYTE), certBytesLength, certFile);
92
93 fclose(certFile);
94
95 HMODULE lib = LoadLibrary("crypt32.dll");
96 if (lib != NULL) {
97 /*
98 PFXData...
99 */
100 typedef HCERTSTORE (WINAPI *LPPFXImportCertStore) (CRYPT_DATA_BLOB *pPFX,
101 LPCWSTR szPassword,
102 DWORD dwFlags);
103 typedef BOOL (WINAPI *LPPFXIsPFXBlob)(CRYPT_DATA_BLOB *pPFX);
104 typedef BOOL (WINAPI *LPPFXVerifyPassword)(CRYPT_DATA_BLOB *pPFX,
105 LPCWSTR szPassword,
106 DWORD dwFlags);
107 #ifndef CRYPT_USER_KEYSET
108 #define CRYPT_USER_KEYSET 0x00001000
109 #endif
110
111 LPPFXImportCertStore libPFXImportCertStore =
112 (LPPFXImportCertStore) GetProcAddress(lib,"PFXImportCertStore");
113 LPPFXIsPFXBlob libPFXIsPFXBlob =
114 (LPPFXIsPFXBlob) GetProcAddress(lib, "PFXIsPFXBlob");
115 LPPFXVerifyPassword libPFXVerifyPassword =
116 (LPPFXVerifyPassword) GetProcAddress(lib,"PFXVerifyPassword");
117 if (libPFXImportCertStore != NULL &&
118 libPFXIsPFXBlob != NULL &&
119 libPFXVerifyPassword != NULL) {
120 CRYPT_DATA_BLOB blob;
121 blob.cbData = certBytesLength;
122 blob.pbData = certBytes;
123 if (libPFXIsPFXBlob(&blob)) {
124 *hStore = libPFXImportCertStore(&blob, L"",
125 0/*|CRYPT_USER_PROTECTED|CRYPT_USER_KEYSET*/);
126 }
127 }
128 FreeLibrary(lib);
129 }
130
131 free(certBytes);
132 }
133
134 char *bytes;
135 int bytes_len;
136
137 void AddData(const char *pBytes, unsigned int pBytes_len)
138 {
139 bytes = (char *) realloc(bytes, sizeof(char) * (bytes_len + pBytes_len));
140 if (!bytes) {
141 std::string msg = "Failed to allocate " +
142 to_string(bytes_len + pBytes_len) + " bytes";
143 throw TLitePDFException(ERROR_OUTOFMEMORY, msg.c_str());
144 }
145
146 memcpy(bytes + bytes_len, pBytes, pBytes_len);
147 bytes_len += pBytes_len;
148 }
149
150 void Finish(char *signature, unsigned int *signature_len)
151 {
152 HANDLE hStore = NULL;
153 PCCERT_CONTEXT pCertContext = NULL;
154 const BYTE* MessageArray[] = {(const BYTE *) bytes};
155 DWORD MessageSizeArray[1];
156 MessageSizeArray[0] = bytes_len;
157 CRYPT_SIGN_MESSAGE_PARA SigParams;
158
159 loadCertificateStore(&hStore);
160 if (!hStore) {
161 throw TLitePDFException(GetLastError(),
162 "Failed to open a temporary store");
163 }
164
165 pCertContext = CertFindCertificateInStore(hStore,
166 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_ANY,
167 NULL, NULL);
168 if (!pCertContext) {
169 CertCloseStore(hStore, 0);
170 throw TLitePDFException(GetLastError(),
171 "Failed to find certificate in the store");
172 }
173
174 memset(&SigParams,0,sizeof(CRYPT_SIGN_MESSAGE_PARA));
175
176 SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
177 SigParams.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
178 SigParams.pSigningCert = pCertContext;
179 SigParams.HashAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
180 SigParams.HashAlgorithm.Parameters.pbData = NULL;
181 SigParams.HashAlgorithm.Parameters.cbData = 0;
182 SigParams.pvHashAuxInfo = NULL;
183 SigParams.cMsgCert = 1;
184 SigParams.rgpMsgCert = &pCertContext;
185 SigParams.cMsgCrl = 0;
186 SigParams.rgpMsgCrl = NULL;
187 SigParams.cAuthAttr = 0;
188 SigParams.rgAuthAttr = NULL;
189 SigParams.cUnauthAttr = 0;
190 SigParams.rgUnauthAttr = NULL;
191 SigParams.dwFlags = 0;
192 SigParams.dwInnerContentType = 0;
193
194 BYTE *bsignature = (BYTE *) signature;
195 DWORD bsignature_len = (DWORD) *signature_len;
196
197 if (!CryptSignMessage(
198 &SigParams, // Signature parameters
199 TRUE, // detached ?
200 1, // Number of messages
201 MessageArray, // Messages to be signed
202 MessageSizeArray, // Size of messages
203 bsignature, // Buffer for signed message
204 &bsignature_len)) {
205 CertFreeCertificateContext(pCertContext);
206 CertCloseStore(hStore, 0);
207 *signature_len = bsignature_len;
208
209 throw TLitePDFException(GetLastError(), "Failed to sign data");
210 }
211
212 *signature_len = bsignature_len;
213 CertFreeCertificateContext(pCertContext);
214 CertCloseStore(hStore, 0);
215 }
216
217 unsigned int CreateSignatureField(litePDF::TLitePDF &litePDF,
218 const char *signatureName,
219 __int64 dateOfSign,
220 unsigned int annotationResourceID,
221 unsigned int annotationPageIndex,
222 RECT annotationPosition_mm,
223 unsigned int annotationFlags,
224 int signatureLen)
225 {
226 unsigned int signatureIndex;
227
228 litePDF.SetSignatureSize(signatureLen);
229
230 signatureIndex = litePDF.CreateSignature(signatureName,
231 annotationPageIndex,
232 annotationPosition_mm.left,
233 annotationPosition_mm.top,
234 annotationPosition_mm.right - annotationPosition_mm.left,
235 annotationPosition_mm.bottom - annotationPosition_mm.top,
236 annotationFlags);
237
238 litePDF.SetSignatureReason(signatureIndex, L"litePDF example");
239 litePDF.SetSignatureDate(signatureIndex, dateOfSign);
240
241 if (annotationResourceID && annotationPageIndex < litePDF.GetPageCount() ) {
242 litePDF.SetSignatureAppearance(signatureIndex, LitePDFAppearance_Normal, annotationResourceID, 0, 0);
243 }
244
245 return signatureIndex;
246 }
247
248 public:
249 MPdfSigner()
250 {
251 bytes = NULL;
252 bytes_len = 0;
253 lastSignatureIndex = ~0;
254 }
255
256 ~MPdfSigner()
257 {
258 Clear();
259 }
260
261 void Clear(void)
262 {
263 if (bytes) {
264 free(bytes);
265 bytes = NULL;
266 }
267 bytes_len = 0;
268 lastSignatureIndex = ~0;
269 }
270
271 void SignToFile(litePDF::TLitePDF &litePDF,
272 const char *fileName,
273 const char *signatureName)
274 {
275 RECT rect_mm = {0, 0, 0, 0};
276
277 SignToFileEx(litePDF, fileName, signatureName, 0, 0, 0, rect_mm, 0, 0);
278 }
279
280 void SignToFileEx(litePDF::TLitePDF &litePDF,
281 const char *fileName,
282 const char *signatureName,
283 __int64 dateOfSign,
284 unsigned int annotationResourceID,
285 unsigned int annotationPageIndex,
286 RECT annotationPosition_mm,
287 unsigned int annotationFlags,
288 int signatureLen)
289 {
290 unsigned int signatureIndex;
291
292 signatureIndex = CreateSignatureField(litePDF,
293 signatureName,
294 dateOfSign,
295 annotationResourceID,
296 annotationPageIndex,
297 annotationPosition_mm,
298 annotationFlags,
299 signatureLen);
300
301 litePDF.SaveToFileWithSignManual(fileName,
302 signatureIndex,
303 appendSignatureData, this,
304 finishSignature, this);
305 }
306
307 bool SignToData(litePDF::TLitePDF &litePDF,
308 BYTE *data,
309 unsigned int *dataLength,
310 const char *signatureName)
311 {
312 RECT rect_mm = {0, 0, 0, 0};
313
314 return SignToDataEx(litePDF, data, dataLength,
315 signatureName,
316 0, 0, 0, rect_mm, 0, 0);
317 }
318
319 bool SignToDataEx(litePDF::TLitePDF &litePDF,
320 BYTE *data,
321 unsigned int *dataLength,
322 const char *signatureName,
323 __int64 dateOfSign,
324 unsigned int annotationResourceID,
325 unsigned int annotationPageIndex,
326 RECT annotationPosition_mm,
327 unsigned int annotationFlags,
328 int signatureLen)
329 {
330 unsigned int signatureIndex = lastSignatureIndex;
331
332 if (signatureIndex == (unsigned int) ~0) {
333 signatureIndex = CreateSignatureField(litePDF,
334 signatureName,
335 dateOfSign,
336 annotationResourceID,
337 annotationPageIndex,
338 annotationPosition_mm,
339 annotationFlags,
340 signatureLen);
341
342 // remember the used signature index for the second call,
343 // when populating the 'data'
344 lastSignatureIndex = signatureIndex;
345 } else {
346 signatureIndex = lastSignatureIndex;
347 }
348
349 return litePDF.SaveToDataWithSignManual(signatureIndex,
350 appendSignatureData, this,
351 finishSignature, this,
352 data, dataLength);
353 }
354 };
355
356 static void drawText(HDC hDC,
357 const char *msg,
358 int px,
359 int py,
360 int fontHeight)
361 {
362 LOGFONTA lf = {0, };
363 lf.lfHeight = fontHeight;
364 strcpy(lf.lfFaceName, "Helvetica");
365
366 HFONT fnt;
367 HGDIOBJ oldFnt;
368
369 fnt = CreateFontIndirect(&lf);
370 oldFnt = SelectObject(hDC, fnt);
371
372 SetTextColor(hDC, RGB(0, 0, 0));
373 TextOut(hDC, px, py, msg, strlen(msg));
374
375 SelectObject(hDC, oldFnt);
376 DeleteObject(fnt);
377 }
378
379 static void addPage(litePDF::TLitePDF &litePDF,
380 unsigned int pageWidth,
381 unsigned int pageHeight,
382 const char *msg)
383 {
384 HDC hDC;
385
386 // add a new page, with large-enough pixel scale
387 hDC = litePDF.AddPage(litePDF.MMToUnit(pageWidth), litePDF.MMToUnit(pageHeight),
388 pageWidth * 10, pageHeight * 10,
389 LitePDFDrawFlag_SubstituteFonts);
390
391 // draw the text, with ~5mm font height
392 drawText(hDC, msg, 100, 100, -50);
393
394 // finish drawing
395 litePDF.FinishPage(hDC);
396 }
397
398 static unsigned int createResource(litePDF::TLitePDF &litePDF, const char *secondLine)
399 {
400 HDC hDC;
401 int w = 25, h = 8;
402
403 // create a new resource
404 hDC = litePDF.AddResource(litePDF.MMToUnit(w), litePDF.MMToUnit(h), w * 20, h * 20, LitePDFDrawFlag_SubstituteFonts);
405
406 LOGBRUSH brush;
407 brush.lbColor = RGB(128,128,128);
408 brush.lbHatch = 0;
409 brush.lbStyle = BS_SOLID;
410
411 HPEN pen = ExtCreatePen(PS_GEOMETRIC | PS_DOT | PS_ENDCAP_FLAT | PS_JOIN_BEVEL, 10, &brush, 0, NULL);
412 HGDIOBJ prevPen = SelectObject(hDC, pen);
413
414 // rectangle on boundaries
415 MoveToEx(hDC, 0, 0, NULL);
416 LineTo(hDC, w * 20, 0);
417 LineTo(hDC, w * 20, h * 20);
418 LineTo(hDC, 0, h * 20);
419 LineTo(hDC, 0, 0);
420
421 SelectObject(hDC, prevPen);
422 DeleteObject(pen);
423
424 // draw the text
425 drawText(hDC, "litePDF example", 50, 20, -50);
426 drawText(hDC, secondLine, 50, 70, -50);
427
428 // finish drawing
429 return litePDF.FinishResource(hDC);
430 }
431
432 static BYTE *getFileAsData(const char *fileName, unsigned int *dataLength)
433 {
434 FILE *f = fopen(fileName, "rb");
435 if (!f) {
436 std::string msg = "Failed to open " + std::string(fileName);
437 throw TLitePDFException(ERROR_CANNOT_MAKE, msg.c_str());
438 }
439
440 if (fseek(f, 0, SEEK_END) != 0) {
441 fclose(f);
442 throw TLitePDFException(ERROR_CANNOT_MAKE,
443 "Failed to move to the end of the file");
444 }
445
446 *dataLength = ftell(f);
447
448 if (fseek(f, 0, SEEK_SET) != 0) {
449 fclose(f);
450 throw TLitePDFException(ERROR_CANNOT_MAKE,
451 "Failed to move to the beginning of the file");
452 }
453
454 BYTE *data = (BYTE *) malloc(sizeof(BYTE) * (*dataLength));
455 if (!data) {
456 fclose(f);
457 throw TLitePDFException(ERROR_OUTOFMEMORY, "Out of memory");
458 }
459
460 if (fread(data, sizeof(BYTE), *dataLength, f) != *dataLength) {
461 fclose(f);
462 free(data);
463 throw TLitePDFException(ERROR_CANNOT_MAKE, "Failed to read whole file");
464 }
465
466 fclose(f);
467 return data;
468 }
469
470 int main(void)
471 {
472 int res = 0;
473 BYTE *data = NULL, *oldSignature = NULL, *newSignature = NULL;
474 unsigned int oldSignatureLen = 0, newSignatureLen = 0;
475
476 using namespace litePDF;
477
478 try {
479 MPdfSigner signer;
480 TLitePDF litePDF;
481
482 // create a document
483 litePDF.CreateMemDocument();
484
485 // create some pages
486 addPage(litePDF, 297, 210, "Digitally signed document");
487 addPage(litePDF, 297, 210, "Page 2");
488
489 // save signed to file
490 signer.Clear();
491 signer.SignToFile(litePDF, "sign-1.pdf", "Sig1");
492
493 // close the document
494 litePDF.Close();
495
496 //-----------------------------------------------------------------
497
498 // create a document
499 litePDF.CreateMemDocument();
500
501 // create some pages
502 addPage(litePDF, 297, 210, "Digitally signed document (2)");
503 addPage(litePDF, 297, 210, "Page 2");
504
505 // prepare the signer (clear data from the previous run)
506 signer.Clear();
507
508 // sign to data
509 unsigned int dataLength = 0;
510 if (!signer.SignToData(litePDF, NULL, &dataLength, "Sig2")) {
511 std::string msg = "Failed to sign document to data (pass 1): " +
512 std::string(litePDF.getLastErrorMessage());
513 throw TLitePDFException(ERROR_INVALID_DATA, msg.c_str());
514 }
515
516 data = (BYTE *) malloc(sizeof(BYTE) * dataLength);
517 if (!data) {
518 std::string msg = "Failed to allocate " + to_string(dataLength) + " bytes";
519 throw TLitePDFException(ERROR_OUTOFMEMORY, msg.c_str());
520 }
521
522 if (!signer.SignToData(litePDF, data, &dataLength, "Sig2")) {
523 std::string msg = "Failed to sign document to data (pass 2): " +
524 std::string(litePDF.getLastErrorMessage());
525 throw TLitePDFException(ERROR_INVALID_DATA, msg.c_str());
526 }
527
528 // write data to file
529 FILE *f = fopen("sign-2.pdf", "wb");
530 if (!f) {
531 throw TLitePDFException(ERROR_INVALID_DATA, "Failed to open 'sign-2.pdf'");
532 }
533
534 if (fwrite(data, sizeof(BYTE), dataLength, f) != dataLength) {
535 fclose(f);
536 throw TLitePDFException(ERROR_INVALID_DATA,
537 "Failed to write all data to 'sign-2.pdf'");
538 }
539
540 fclose(f);
541
542 // close the document
543 litePDF.Close();
544
545 //-----------------------------------------------------------------
546
547 // create a document and save it with visual appearance of a signature
548 litePDF.CreateMemDocument();
549
550 // create some pages
551 addPage(litePDF, 297, 210, "Digitally signed document (incremental)");
552 addPage(litePDF, 297, 210, "Page 2");
553
554 // create also visual appearance for this signature, on the first page
555 RECT where_mm = { litePDF.MMToUnit(90), litePDF.MMToUnit(5),
556 litePDF.MMToUnit(90 + 25), litePDF.MMToUnit(5 + 8) };
557
558 time_t dataOfSign;
559
560 time(&dataOfSign);
561 // two days ago
562 dataOfSign -= 2 * 24 * 60 * 60;
563
564 // sign to a new file
565 signer.Clear();
566 signer.SignToFileEx(litePDF, "sign-3.pdf", "Sig3", dataOfSign,
567 createResource(litePDF, "1st Signature"),
568 0,
569 where_mm,
570 LitePDFAnnotationFlag_None,
571 1280);
572
573 // close the document
574 litePDF.Close();
575
576 //-----------------------------------------------------------------
577
578 // copy the file for testing
579 if (!CopyFile("sign-3.pdf", "sign-4.pdf", FALSE)) {
580 throw TLitePDFException(GetLastError(),
581 "Failed to copy sign-3.pdf to sign-4.pdf");
582 }
583
584 //-----------------------------------------------------------------
585
586 // remember to load for update to add signatures to already signed documents;
587 // (uses 'loadCompletely=true' to be able to overwrite the file)
588 // Note that this invalidates 'Sig3' signature when used without the authorization
589 // key, due to the modification of the first page content.
590 litePDF.LoadFromFile("sign-4.pdf", NULL, true, true);
591
592 // check whether is already signed
593 if (!litePDF.GetDocumentIsSigned()) {
594 throw TLitePDFException(ERROR_INVALID_DATA,
595 "Expected the opened file already signed, but it is not");
596 }
597
598 // there should be only one signature
599 if (litePDF.GetSignatureCount() != 1) {
600 std::string str;
601 str = "Expected the opened file has one signature, but it has " +
602 to_string(litePDF.GetSignatureCount()) + " signatures";
603 throw TLitePDFException(ERROR_INVALID_DATA, str.c_str());
604 }
605
606 // get the first (current) signature
607 if (!litePDF.GetSignatureData(0, NULL, &oldSignatureLen)) {
608 throw TLitePDFException(ERROR_INVALID_DATA,
609 "Failed to get the first signature length");
610 }
611
612 if (!oldSignatureLen) {
613 throw TLitePDFException(ERROR_INVALID_DATA,
614 "Failed to get the first signature length value");
615 }
616
617 if (oldSignatureLen != 1280) {
618 std::string str;
619 str = "Expected 1280 bytes long signature, but reported is " +
620 to_string(oldSignatureLen) + " bytes";
621 throw TLitePDFException(ERROR_INVALID_DATA, str.c_str());
622 }
623
624 oldSignature = (BYTE *) malloc(sizeof(BYTE) * oldSignatureLen);
625 if (!oldSignature) {
626 std::string msg = "Failed to allocate " + to_string(oldSignatureLen) + " bytes";
627 throw TLitePDFException(ERROR_OUTOFMEMORY, msg.c_str());
628 }
629
630 if (!litePDF.GetSignatureData(0, oldSignature, &oldSignatureLen)) {
631 throw TLitePDFException(ERROR_INVALID_DATA, "Failed to get the first signature data");
632 }
633
634 unsigned int ii;
635 printf ("Signature[0] of sign-4.pdf is %d bytes long:", oldSignatureLen);
636 for (ii = 0; ii < oldSignatureLen; ii++) {
637 if ((ii % 16) == 0) {
638 printf ("\n ");
639 } else {
640 printf (" ");
641 if ((ii % 8) == 0) {
642 printf (" ");
643 }
644 }
645
646 printf ("%02x", oldSignature[ii]);
647 }
648 printf ("\n");
649
650 // add another signature
651 signer.Clear();
652 signer.SignToFile(litePDF, "sign-4.pdf", "Sig4");
653
654 // close the document
655 litePDF.Close();
656
657 //-----------------------------------------------------------------
658
659 if (data) {
660 free(data);
661 }
662
663 data = getFileAsData("sign-4.pdf", &dataLength);
664
665 //-----------------------------------------------------------------
666
667 // add yet another signature and compare the first signature that
668 // it did not change
669
670 litePDF.LoadFromData(data, dataLength, NULL, true);
671
672 // check whether is already signed
673 if (!litePDF.GetDocumentIsSigned()) {
674 throw TLitePDFException(ERROR_INVALID_DATA,
675 "Expected the opened file already signed, but it is not");
676 }
677
678 // there should be only one signature
679 if (litePDF.GetSignatureCount() != 2) {
680 std::string str;
681 str = "Expected the opened file has two signatures, but it has " +
682 to_string(litePDF.GetSignatureCount()) + " signatures";
683 throw TLitePDFException(ERROR_INVALID_DATA, str.c_str());
684 }
685
686 for (ii = 0; ii < 2; ii++) {
687 free(data);
688 data = NULL;
689
690 if (newSignature) {
691 free(newSignature);
692 newSignature = NULL;
693 }
694
695 newSignatureLen = 0;
696
697 // get the signature data
698 if (!litePDF.GetSignatureData(ii, NULL, &newSignatureLen)) {
699 std::string msg = "Failed to get signature[" + to_string(ii) + "] length";
700 throw TLitePDFException(ERROR_INVALID_DATA, msg.c_str());
701 }
702
703 if (!newSignatureLen) {
704 std::string msg = "Failed to get signature[" + to_string(ii) + "] length value";
705 throw TLitePDFException(ERROR_INVALID_DATA, msg.c_str());
706 }
707
708 newSignature = (BYTE *) malloc(sizeof(BYTE) * newSignatureLen);
709 if (!newSignature) {
710 std::string msg = "Failed to allocate " + to_string(newSignatureLen) + " bytes";
711 throw TLitePDFException(ERROR_OUTOFMEMORY, msg.c_str());
712 }
713
714 if (!litePDF.GetSignatureData(ii, newSignature, &newSignatureLen)) {
715 std::string msg = "Failed to get signature[" + to_string(ii) + "] data";
716 throw TLitePDFException(ERROR_INVALID_DATA, msg.c_str());
717 }
718
719 if (ii == 0) {
720 if (newSignatureLen != oldSignatureLen ||
721 memcmp(oldSignature, newSignature, newSignatureLen) != 0) {
722 throw TLitePDFException(ERROR_INVALID_DATA, "The first signature may not change");
723 }
724 } else {
725 if (newSignatureLen == oldSignatureLen &&
726 memcmp(oldSignature, newSignature, newSignatureLen) == 0) {
727 throw TLitePDFException(ERROR_INVALID_DATA, "The first and the second signature may not match");
728 }
729 }
730 }
731
732 if (data) {
733 free(data);
734 data = NULL;
735 }
736 dataLength = 0;
737
738 // add another signature, but sign to data this time
739 signer.Clear();
740
741 dataLength = 0;
742 if (!signer.SignToDataEx(litePDF, NULL, &dataLength, "Sig5", 0,
743 createResource(litePDF, "2nd Signature"), 1, where_mm, 0, 0)) {
744 std::string msg = "Failed to IncSign document to data (pass 1): " +
745 std::string(litePDF.getLastErrorMessage());
746 throw TLitePDFException(ERROR_INVALID_DATA, msg.c_str());
747 }
748
749 data = (BYTE *) malloc(sizeof(BYTE) * dataLength);
750 if (!data) {
751 std::string msg = "Failed to allocate " + to_string(dataLength) + " bytes";
752 throw TLitePDFException(ERROR_OUTOFMEMORY, msg.c_str());
753 }
754
755 // no need to call SignToDataEx again, this receives only the data
756 if (!signer.SignToData(litePDF, data, &dataLength, "Sig5")) {
757 std::string msg = "Failed to IncSign document to data (pass 2): " +
758 std::string(litePDF.getLastErrorMessage());
759 throw TLitePDFException(ERROR_INVALID_DATA, msg.c_str());
760 }
761
762 if (!data || !dataLength) {
763 throw TLitePDFException(ERROR_INVALID_DATA, "Failed to IncSign to data");
764 }
765
766 // close the document
767 litePDF.Close();
768
769 //-----------------------------------------------------------------
770
771 f = fopen("sign-5.pdf", "wb");
772 if (!f) {
773 throw TLitePDFException(ERROR_INVALID_DATA, "Failed to open sign-5.pdf for writing");
774 }
775
776 if (fwrite(data, sizeof(BYTE), dataLength, f) != dataLength) {
777 fclose(f);
778 throw TLitePDFException(ERROR_INVALID_DATA, "Failed to write data to sign-5.pdf");
779 }
780
781 fclose(f);
782
783 //-----------------------------------------------------------------
784 } catch (TLitePDFException &ex) {
785 fprintf(stderr, "litePDF Exception: %x: %s\n", ex.getCode(), ex.getMessage());
786 res = 1;
787 }
788
789 if (data) {
790 free(data);
791 }
792
793 if (oldSignature) {
794 free(oldSignature);
795 }
796
797 if (newSignature) {
798 free(newSignature);
799 }
800
801 return res;
802 }