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