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 }