Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid using memory buffer to store the entire pdf document when making a digital signature #20

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions demo_raster_encoder/demo_raster_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ int write_bitonal_uncompressed_signed_file(t_OS os, const char* filename, const
char* demo = strstr(image_path, "demo_raster_encoder");
strncpy(cert_path, image_path, demo - image_path);
sprintf(cert_path + (demo - image_path), "%s", "certificate.p12");
t_pdfrasencoder* enc = pdfr_signed_encoder_create(PDFRAS_API_LEVEL, &os, cert_path, "");
t_pdfrasencoder* enc = pdfr_signed_encoder_create(PDFRAS_API_LEVEL, &os, filename, cert_path, "");
pdfr_encoder_set_creator(enc, "raster_encoder_demo 1.0");
pdfr_encoder_set_subject(enc, "BW 1-bit Uncompressed sample output");

Expand Down Expand Up @@ -314,7 +314,7 @@ int write_bitonal_uncompressed_signed_and_encrypted_file(t_OS os, const char* fi
char* demo = strstr(image_path, "demo_raster_encoder");
strncpy(cert_path, image_path, demo - image_path);
sprintf(cert_path + (demo - image_path), "%s", "certificate.p12");
t_pdfrasencoder* enc = pdfr_signed_encoder_create(PDFRAS_API_LEVEL, &os, cert_path, "");
t_pdfrasencoder* enc = pdfr_signed_encoder_create(PDFRAS_API_LEVEL, &os, filename, cert_path, "");
pdfr_encoder_set_AES128_encrypter(enc, "open", "master", PDFRAS_PERM_COPY_FROM_DOCUMENT, PD_TRUE);

pdfr_encoder_set_creator(enc, "raster_encoder_demo 1.0");
Expand Down
112 changes: 112 additions & 0 deletions pdfras_digitalsignature/pdfras_digitalsignature.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ struct t_digitalsignature {
X509_STORE* cert_store;
};

struct t_sign_file_bio {
FILE* fd;
t_sign_range* ranges;
pdint32 ranges_length;
pdint32 pos;
pduint32 read_bytes;
pdbool eof;
pdbool init;
};

pdbool static load_certificate(t_signer* signer, const char* file, const char* password) {
PKCS12* pkcs12 = NULL;
FILE* pfx_file = NULL;
Expand Down Expand Up @@ -152,6 +162,108 @@ pdint32 pdfr_digsig_signature_length(t_digitalsignature* ds) {
return ret;
}

static int sign_range_bio_create(BIO* b) {
BIO_set_init(b, 1);
return 1;
}

static int sign_range_bio_destroy(BIO* b) {
return 0;
}

static int sign_range_bio_read(BIO* b, char* buf, int len) {
struct t_sign_file_bio* sign_bio_data = BIO_get_data(b);
t_sign_range* ranges = sign_bio_data->ranges;
t_sign_range* current_range;
FILE* fd = sign_bio_data->fd;
int ret = -1;

if (sign_bio_data->eof || sign_bio_data->pos >= sign_bio_data->ranges_length)
return -1;

current_range = &ranges[sign_bio_data->pos];
if (!sign_bio_data->init) {
fseek(fd, current_range->offset, SEEK_SET);
sign_bio_data->init = PD_TRUE;
}
// if length of bytes to read overflow the current range then try
// move to next range or reduce it to the current range boundary
while (sign_bio_data->read_bytes + len > current_range->len) {
int len_ = current_range->len - sign_bio_data->read_bytes;
if (len_ <= 0) {
if (sign_bio_data->pos + 1 >= sign_bio_data->ranges_length) {
sign_bio_data->eof = PD_TRUE;
break;
}
// move to next range
sign_bio_data->pos++;
current_range++;
sign_bio_data->read_bytes = 0;
fseek(fd, current_range->offset, SEEK_SET);
}
else {
len = len_;
}
}
if (!sign_bio_data->eof) {
ret = fread(buf, 1, len, fd);
if (ret > 0) {
sign_bio_data->read_bytes += ret;
}
}

return ret;
}

// sign data from an input file
pdint32 pdfr_digsig_sign_range(t_digitalsignature* ds, FILE* fd, t_sign_range* ranges, pdint32 ranges_length, pduint8* output, const pduint32 output_length) {
assert(ds);
assert(ds->signer);
pdint32 ret = -1;
struct t_sign_file_bio signer_bio_data = {.fd = fd,
.ranges = ranges,
.ranges_length = ranges_length,
.pos = 0,
.read_bytes = 0,
.init = PD_FALSE,
.eof = PD_FALSE
};
BIO_METHOD* meth = BIO_meth_new(BIO_TYPE_FD, "sign-range-content-bio");

BIO_meth_set_read(meth, sign_range_bio_read);
BIO_meth_set_create(meth, sign_range_bio_create);
BIO_meth_set_destroy(meth, sign_range_bio_destroy);

BIO* inputbio = BIO_new(meth);
if (inputbio == NULL)
return -1;

BIO_set_data(inputbio, &signer_bio_data);
PKCS7* pkcs7;
pduint32 flags = PKCS7_DETACHED | PKCS7_BINARY;
pkcs7 = PKCS7_sign(ds->signer->digsig_cert, ds->signer->digsig_pkey, NULL, inputbio, flags);

BIO_free(inputbio);

if (pkcs7) {
BIO* outputbio = BIO_new(BIO_s_mem());
i2d_PKCS7_bio(outputbio, pkcs7);

BUF_MEM* mem = NULL;
BIO_get_mem_ptr(outputbio, &mem);

if (mem && mem->data && output_length >= mem->length) {
ret = (pdint32)mem->length;
memcpy(output, mem->data, mem->length);
}

BIO_free(outputbio);
PKCS7_free(pkcs7);
}

return ret;
}

// sign data
pdint32 pdfr_digsig_sign_data(t_digitalsignature* ds, const pduint8* input, const pdint32 input_length, pduint8* output, const pduint32 output_length) {
assert(ds);
Expand Down
1 change: 1 addition & 0 deletions pdfras_digitalsignature/pdfras_digitalsignature.def
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ EXPORTS
pdfr_digsig_sign_data @4
pdfr_digitalsignature_create_signer @5
pdfr_digitalsignature_validate @6
pdfr_digsig_sign_range @7
10 changes: 9 additions & 1 deletion pdfras_digitalsignature/pdfras_digitalsignature.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
extern "C" {
#endif

#include <stdio.h>
#include "PdfPlatform.h"

#define DS_DOC_NOT_CHANGED 0x1 // Document has not been changed
Expand All @@ -15,6 +16,10 @@ extern "C" {

typedef struct t_signer t_signer;
typedef struct t_digitalsignature t_digitalsignature;
typedef struct {
pduint32 offset;
pduint32 len;
} t_sign_range;

// Initiliaze digital signature module
// return: t_digitalsignature object
Expand Down Expand Up @@ -48,7 +53,10 @@ typedef pdint32 (PDFRASAPICALL pfn_pdfr_digitalsignature_validate) (t_digitalsig
// output_length: size of buffer for signed data.
// If it smaller than signed data computed in function than function will return -1.
pdint32 PDFRASAPICALL pdfr_digsig_sign_data(t_digitalsignature* ds, const pduint8* input, const pdint32 input_length, pduint8* output, const pduint32 output_length);
typedef pdint32(PDFRASAPICALL *pfn_pdfr_digisig_sign_data) (t_digitalsignature* ds, const pduint8* input, const pdint32 input_length, const pduint8* output, const pduint32 output_length);
typedef pdint32(PDFRASAPICALL *pfn_pdfr_digisig_sign_data) (t_digitalsignature* ds, const pduint8* input, const pdint32 input_length, pduint8* output, const pduint32 output_length);

pdint32 PDFRASAPICALL pdfr_digsig_sign_range(t_digitalsignature* ds, FILE* fd, t_sign_range* ranges, pdint32 ranges_length, pduint8* output, const pduint32 output_length);
typedef pdint32(PDFRASAPICALL* pfn_pdfr_digsig_sign_range) (t_digitalsignature* ds, FILE* fd, t_sign_range* ranges, pdint32 ranges_length, pduint8* output, const pduint32 output_length);

#ifdef __cplusplus
}
Expand Down
Loading