On Thu, 2015-03-05 at 13:12 -0800, Danny Liberty wrote:
> Does anyone have a code example of how to use this new functionality
> in PoDoFo 0.9.3?                                        


        Hi,
I know this is very late, but maybe someone will find this useful.
The code is similar to usual signing and it uses Windows Crypto API.
        Bye,
        zyx

-- 
http://www.litePDF.cz                                 i...@litepdf.cz
#include <windows.h>
#include <wincrypt.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <string>

#include "podofo.h"

using namespace PoDoFo;

// Link with the crypt32.lib file
#pragma comment (lib, "crypt32.lib")

using namespace PoDoFo;

static double MM_TO_POINTS(double mm)
{
   double pts = (((mm) / 25.4) * 72.0);
   if (pts < 0) {
      pts -= 1e-6;
   } else {
      pts += 1e-6;
   }
   return pts;
}


class MPdfSigner
{
 private:
   static PdfFont *
   createFont (PdfDocument *document,
               void *user_data)
   {
      return document->CreateFont("Helvetica", FALSE, PdfEncodingFactory::GlobalWinAnsiEncodingInstance());
   }

   void loadCertificateStore(HANDLE *hStore)
   {
      BYTE *certBytes = NULL;
      unsigned int certBytesLength = 0;

      FILE *certFile = fopen("cert.pfx", "rb");
      if (!certFile) {
         fprintf(stderr, "Failed to open cert.pfx\n");
         PODOFO_RAISE_ERROR (ePdfError_FileNotFound);
      }

      fseek(certFile, 0, SEEK_END);
      certBytesLength = ftell(certFile);
      fseek(certFile, 0, SEEK_SET);
      certBytes = (BYTE *) malloc(sizeof(BYTE) * certBytesLength);
      if (!certBytes) {
         fprintf(stderr, "Failed to allocate memory for cert.pfx");
         PODOFO_RAISE_ERROR (ePdfError_OutOfMemory);
      }

      fread(certBytes, sizeof(BYTE), certBytesLength, certFile);

      fclose(certFile);

      HMODULE lib = LoadLibrary("crypt32.dll");
      if (lib != NULL) {
         /*
            PFXData...
         */
         typedef HCERTSTORE (WINAPI *LPPFXImportCertStore) (CRYPT_DATA_BLOB *pPFX,
                                                            LPCWSTR szPassword,
                                                            DWORD dwFlags);
         typedef BOOL (WINAPI *LPPFXIsPFXBlob)(CRYPT_DATA_BLOB *pPFX);
         typedef BOOL (WINAPI *LPPFXVerifyPassword)(CRYPT_DATA_BLOB *pPFX,
                                                    LPCWSTR szPassword,
                                                    DWORD dwFlags);
         #ifndef CRYPT_USER_KEYSET
         #define CRYPT_USER_KEYSET         0x00001000     
         #endif

         LPPFXImportCertStore libPFXImportCertStore =
               (LPPFXImportCertStore) GetProcAddress(lib,"PFXImportCertStore");
         LPPFXIsPFXBlob libPFXIsPFXBlob =
               (LPPFXIsPFXBlob) GetProcAddress(lib, "PFXIsPFXBlob");
         LPPFXVerifyPassword libPFXVerifyPassword =
               (LPPFXVerifyPassword) GetProcAddress(lib,"PFXVerifyPassword");
         if (libPFXImportCertStore != NULL &&
             libPFXIsPFXBlob != NULL &&
             libPFXVerifyPassword != NULL) {
            CRYPT_DATA_BLOB blob;
            blob.cbData = certBytesLength;
            blob.pbData = certBytes;
            if (libPFXIsPFXBlob(&blob)) {
               *hStore = libPFXImportCertStore(&blob, L"",
                     0/*|CRYPT_USER_PROTECTED|CRYPT_USER_KEYSET*/);
            }
         }
         FreeLibrary(lib);
      }

      free(certBytes);
   }

   char *bytes;
   int bytes_len;

   void AddData(const char *pBytes, unsigned int pBytes_len)
   {
      bytes = (char *) realloc(bytes, sizeof(char) * (bytes_len + pBytes_len));
      if (!bytes) {
         PODOFO_RAISE_ERROR (ePdfError_OutOfMemory);
      }

      memcpy(bytes + bytes_len, pBytes, pBytes_len);
      bytes_len += pBytes_len;
   }

   void Finish(char *signature, unsigned int *signature_len)
   {
      HANDLE hStore = NULL;
      PCCERT_CONTEXT pCertContext = NULL;
      const BYTE* MessageArray[] = {(const BYTE *) bytes};
      DWORD MessageSizeArray[1];
      MessageSizeArray[0] = bytes_len;
      CRYPT_SIGN_MESSAGE_PARA  SigParams;

      loadCertificateStore(&hStore);
      if (!hStore) {
         fprintf (stderr, "Failed to open temporary store\n");
         PODOFO_RAISE_ERROR (ePdfError_InvalidHandle);
      }

      pCertContext = CertFindCertificateInStore(hStore,
            PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_ANY,
            NULL, NULL);
      if (!pCertContext) {
         CertCloseStore(hStore, 0);
         fprintf (stderr, "Failed to find certificate in the store\n");
         PODOFO_RAISE_ERROR (ePdfError_InvalidHandle);
      }

      memset(&SigParams,0,sizeof(CRYPT_SIGN_MESSAGE_PARA));

      SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
      SigParams.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
      SigParams.pSigningCert = pCertContext;
      SigParams.HashAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
      SigParams.HashAlgorithm.Parameters.pbData = NULL;
      SigParams.HashAlgorithm.Parameters.cbData = 0;
      SigParams.pvHashAuxInfo = NULL;
      SigParams.cMsgCert = 1;
      SigParams.rgpMsgCert = &pCertContext;
      SigParams.cMsgCrl = 0;
      SigParams.rgpMsgCrl = NULL;
      SigParams.cAuthAttr = 0;
      SigParams.rgAuthAttr = NULL;
      SigParams.cUnauthAttr = 0;
      SigParams.rgUnauthAttr = NULL;
      SigParams.dwFlags = 0;
      SigParams.dwInnerContentType = 0;

      BYTE *bsignature = (BYTE *) signature;
      DWORD bsignature_len = (DWORD) *signature_len;

      if (!CryptSignMessage(
            &SigParams,            // Signature parameters
            TRUE,                  // detached ?
            1,                     // Number of messages
            MessageArray,          // Messages to be signed
            MessageSizeArray,      // Size of messages
            bsignature,            // Buffer for signed message
            &bsignature_len)) {
         CertFreeCertificateContext(pCertContext);
         CertCloseStore(hStore, 0);
         *signature_len = bsignature_len;

         fprintf (stderr, "Failed to sign data\n");
         PODOFO_RAISE_ERROR (ePdfError_InvalidHandle);
      }

      *signature_len = bsignature_len;
      CertFreeCertificateContext(pCertContext);
      CertCloseStore(hStore, 0);
   }

   bool
   incSignToOutputDevice(PdfSigIncMemDocument &document,
                         PdfSignOutputDevice &signer)
   {
      if (!document.GetPageCount()) {
         fprintf (stderr, "Document has no page\n");
         return false;
      }

      /* optional visual appearance of the signature */
      if (true) {
         int pageIndex = 0;
         PdfPage *page = document.GetPage(pageIndex);
         if (!page) {
            fprintf (stderr, "Page #%d not found\n", pageIndex);
            return false;
         }

         double x, y, w, h, fh;
         const char *fontName = NULL;

         x = MM_TO_POINTS(50);
         y = MM_TO_POINTS(130);
         w = MM_TO_POINTS(45);
         h = MM_TO_POINTS(20);
         fh = MM_TO_POINTS(10);

         document.GetSignatureField()->SetSignatureText(L"Signature\ntext", pageIndex, x, y, w, h, fh, "Helvetica", false, NULL);

         /* image data */
         /*if (image_data && image_dataLength) {
            x = MM_TO_POINTS(image_x_mm);
            y = MM_TO_POINTS(image_y_mm);
            w = MM_TO_POINTS(image_width_mm);
            h = MM_TO_POINTS(image_height_mm);
            document.GetSignatureField()->SetSignatureImage(image_data, image_dataLength, pageIndex, x, y, w, h);
            if (image_mask_threshold >= 0) {
               document.GetSignatureField()->SetImageChromaKeyMask(image_mask_red, image_mask_green, image_mask_blue, image_mask_threshold);
            }
         }*/
      }

      PdfString sigReason;
      sigReason.setFromWchar_t(L"Signature reason");

      signer.SetSignatureSize(4096);

      // Set time of signing
      document.GetSignatureField()->SetSignatureDate(PdfDate());
      document.GetSignatureField()->SetSignatureReason(sigReason);

      document.Initialize();
      document.CreateVisualSign();  

      document.Write(&signer);

      if (!document.GetPageCount()) {
         fprintf (stderr, "No page found after document signed\n");
         return false;
      }

      if (!signer.HasSignaturePosition()) {
         fprintf (stderr, "Cannot find signature position in document data\n");
         return false;
      }

      // Adjust ByteRange for signature
      signer.AdjustByteRange();

      // Read data for signature and count it
      // We seek at the beginning of the file
      signer.Seek(0);

      unsigned int buffLen = 65535, len;
      char *buff;

      while (buff = (char *) malloc(sizeof(char) * buffLen), !buff) {
         buffLen = buffLen / 2;
         if (!buffLen)
            break;
      }

      if (!buff) {
         PODOFO_RAISE_ERROR (ePdfError_OutOfMemory);
      }

      while ((len = signer.ReadForSignature(buff, buffLen)) > 0) {
         AddData(buff, len);
      }

      len = buffLen;
      Finish(buff, &len);

      if (len > 0) {
         PdfData signature(buff, len);
         signer.SetSignature(signature);
      }

      free (buff);

      signer.Flush();

      return true;
   }

 public:
   MPdfSigner()
   {
      bytes = NULL;
      bytes_len = 0;
   }

   ~MPdfSigner()
   {
      Clear();
   }

   void Clear(void)
   {
      if (bytes) {
         free(bytes);
         bytes = NULL;
      }
      bytes_len = 0;
   }

   bool
   incSign (unsigned char *in_data,
	         long in_data_len,
            unsigned char **out_data,
            unsigned int *out_data_len)
   {
	   if (!in_data || in_data_len <= 0) {
         fprintf (stderr, "No data to sign\n");
		   return false;
      }

      PdfSigIncMemDocument document;
      PdfRefCountedInputDevice inputDevice = PdfRefCountedInputDevice((char *) in_data, in_data_len);

      document.Load(inputDevice);
      document.GetSignatureField()->createFontFunc = createFont;

      PdfRefCountedBuffer *signedSavedData = new PdfRefCountedBuffer();
      if (!signedSavedData) {
         fprintf (stderr, "Failed to create signedSavedData\n");
         return false;
      }

      PdfOutputDevice outputDevice(signedSavedData);
      PdfSignOutputDevice signer(&outputDevice);

      if (!incSignToOutputDevice(document, signer)) {
         delete signedSavedData;

         return false;
      }

      *out_data = (unsigned char *) malloc (sizeof (unsigned char) * signedSavedData->GetSize());
      if (!*out_data) {
         delete signedSavedData;
         fprintf (stderr, "Failed to create out_data\n");
         return false;
      }

      memcpy(*out_data, signedSavedData->GetBuffer(), signedSavedData->GetSize());
      *out_data_len = signedSavedData->GetSize();

      delete signedSavedData;

      return true;
   }
};

int
main (int argc,
      char *argv[])
{
	FILE *f = NULL;
	unsigned char *data = NULL;
	
	if (argc <= 1) {
		fprintf (stderr, "Requires at least one argument, a PDF file name\n");
		return 1;
	}

	PdfError::EnableLogging(false);

	try {
		int ii;

		for (ii = 1; ii < argc; ii++) {
			FILE *f = fopen (argv[ii], "rb");
			if (!f) {
				fprintf (stderr, "Failed to open file '%s': (%d) %s\n", argv[ii], errno, strerror (errno));
				return 2;
			}

			fseek (f, 0, SEEK_END);
			long data_len = ftell (f);
			fseek (f, 0, SEEK_SET);
			data = (unsigned char *) malloc (sizeof (unsigned char) * data_len);

			if (!data) {
				fprintf (stderr, "Failed to allocate %d bytes for file '%s'\n", (int) data_len, argv[ii]);
				fclose (f);
				return 3;
			}

			if (fread (data, sizeof (unsigned char), data_len, f) != (size_t) data_len) {
				fprintf (stderr, "Failed to read whole file '%s'\n", argv[ii]);
				fclose (f);
				free (data);
				return 4;
			}

         unsigned char *out_data;
         unsigned int out_data_len;
         MPdfSigner signer;

         if (!signer.incSign(data, data_len, &out_data, &out_data_len)) {
				fprintf (stderr, "Failed to incSign '%s'\n", argv[ii]);
				fclose (f);
				free (data);
				return 5;
         }

			free (data); data = NULL;
			fclose (f);

         std::string flnm = argv[ii];
         flnm += "-signed.pdf";
         f = fopen (flnm.c_str(), "wb");
         if (!f) {
				fprintf (stderr, "Failed to open '%s' for writing\n", flnm.c_str());
            free (out_data);
            return 6;
         }

         if (fwrite (out_data, sizeof (unsigned char), out_data_len, f) != out_data_len) {
				fprintf (stderr, "Failed to write all data to '%s'\n", flnm.c_str());
            free (out_data);
            fclose (f);
            return 7;
         }

         free (out_data);
         fclose (f); f = NULL;
		}
	} catch (const PdfError &error) {
		if (data)
			free (data);
		if (f)
			fclose (f);
		fprintf (stderr, "Failed with error:\n");
		error.PrintErrorMsg();
		return 8;
	}

	if (data)
		free (data);
	if (f)
		fclose (f);

	return 0;
}
------------------------------------------------------------------------------
_______________________________________________
Podofo-users mailing list
Podofo-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/podofo-users

Reply via email to