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