diff --git a/demo_raster_encoder/demo_raster_encoder.c b/demo_raster_encoder/demo_raster_encoder.c index be4330c..06cc0d7 100644 --- a/demo_raster_encoder/demo_raster_encoder.c +++ b/demo_raster_encoder/demo_raster_encoder.c @@ -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"); @@ -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"); diff --git a/pdfras_digitalsignature/pdfras_digitalsignature.c b/pdfras_digitalsignature/pdfras_digitalsignature.c index 62e880f..81b4544 100644 --- a/pdfras_digitalsignature/pdfras_digitalsignature.c +++ b/pdfras_digitalsignature/pdfras_digitalsignature.c @@ -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; @@ -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); diff --git a/pdfras_digitalsignature/pdfras_digitalsignature.def b/pdfras_digitalsignature/pdfras_digitalsignature.def index 7009c00..d5a3742 100644 --- a/pdfras_digitalsignature/pdfras_digitalsignature.def +++ b/pdfras_digitalsignature/pdfras_digitalsignature.def @@ -7,3 +7,4 @@ EXPORTS pdfr_digsig_sign_data @4 pdfr_digitalsignature_create_signer @5 pdfr_digitalsignature_validate @6 + pdfr_digsig_sign_range @7 diff --git a/pdfras_digitalsignature/pdfras_digitalsignature.h b/pdfras_digitalsignature/pdfras_digitalsignature.h index 39f6781..20a6d68 100644 --- a/pdfras_digitalsignature/pdfras_digitalsignature.h +++ b/pdfras_digitalsignature/pdfras_digitalsignature.h @@ -5,6 +5,7 @@ extern "C" { #endif +#include #include "PdfPlatform.h" #define DS_DOC_NOT_CHANGED 0x1 // Document has not been changed @@ -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 @@ -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 } diff --git a/pdfras_writer/PdfDigitalSignature.c b/pdfras_writer/PdfDigitalSignature.c index d12a57a..6e8ee87 100644 --- a/pdfras_writer/PdfDigitalSignature.c +++ b/pdfras_writer/PdfDigitalSignature.c @@ -24,24 +24,11 @@ struct t_digitalsignature { X509_STORE* cert_store; }; -#define BUFFER_SIZE 8192 - -typedef struct { - pduint8* buffer; - pduint32 bufferSize; - pduint32 written; -} t_writer_data; - // data structure for digital signature struct t_pdfdigitalsignature { t_pdmempool* pool; t_pdfrasencoder* encoder; - fOutputWriter userWriter; - void* userCookie; - - // writer data - t_writer_data* data; // data used by pdfras_digitalsignature module t_digitalsignature* ds; @@ -58,11 +45,19 @@ struct t_pdfdigitalsignature { // written to output pdbool written; + // output pdf file + char* pdf_file; + + // mark digital signature + pdbool digisig_finish; + pduint32 digsig_objnum; + pdint32 content_pos_begin, content_pos_end; + pdint32 byterange_pos_begin, byterange_pos_end; }; // Initialization -t_pdfdigitalsignature* digitalsignature_create(t_pdfrasencoder* encoder, const char* pfx_file, const char* password) { +t_pdfdigitalsignature* digitalsignature_create(t_pdfrasencoder* encoder, const char *pdf_file, const char* pfx_file, const char* password) { assert(encoder); t_pdmempool* pool = pdfr_encoder_mempool(encoder); @@ -83,19 +78,8 @@ t_pdfdigitalsignature* digitalsignature_create(t_pdfrasencoder* encoder, const c return NULL; } - digitalSignature->data = (t_writer_data*) pd_alloc(pool, sizeof(t_writer_data)); - - digitalSignature->data->buffer = (pduint8*)pd_alloc(pool, sizeof(pduint8) * BUFFER_SIZE); - if (!digitalSignature->data->buffer) - return NULL; - - digitalSignature->data->bufferSize = BUFFER_SIZE; - digitalSignature->data->written = 0; - digitalSignature->pool = pool; digitalSignature->encoder = encoder; - digitalSignature->userWriter = pdfr_encoder_set_outputwriter(encoder, digitalsignature_writer); - digitalSignature->userCookie = pdfr_encoder_set_cookie(encoder, (void*) digitalSignature); digitalSignature->name = NULL; digitalSignature->location = NULL; @@ -103,111 +87,87 @@ t_pdfdigitalsignature* digitalsignature_create(t_pdfrasencoder* encoder, const c digitalSignature->contact_info = NULL; digitalSignature->written = PD_FALSE; + digitalSignature->digisig_finish = PD_FALSE; digitalSignature->digsig_objnum = 0; - - return digitalSignature; -} - -static pduint8* find_string_in_binary(pduint8* data, const pduint32 data_len, const char* what) { - size_t idx = 0; - size_t what_len = strlen(what); + digitalSignature->content_pos_begin = 0; + digitalSignature->content_pos_end = 0; + digitalSignature->byterange_pos_begin = 0; + digitalSignature->byterange_pos_end = 0; + digitalSignature->pdf_file = (char *)pd_alloc(pool, strlen(pdf_file) + 1); + if (!digitalSignature->pdf_file) + return NULL; - while ((idx < (data_len - what_len))) { - if (memcmp(data + idx, what, what_len) == 0) { - return data + idx; - } + strcpy(digitalSignature->pdf_file, pdf_file); - ++idx; - } + return digitalSignature; +} - return NULL; +void digitalsignature_ready(t_pdfdigitalsignature* signature) { + signature->digisig_finish = PD_TRUE; } void digitalsignature_finish(t_pdfdigitalsignature* signature) { - pduint32 offset1 = 0; - pduint32 length1 = 0; - pduint32 offset2 = 0; - pduint32 length2 = 0; - - pduint8* contents = find_string_in_binary(signature->data->buffer, signature->data->written, "/Contents <"); - if (!contents) + FILE* fd; + char byterange_value[50]; + int byterange_len; + pduint8* content_value; + t_sign_range ranges[2]; + pdint32 signature_len; + pdint32 content_len; + + if (signature->digisig_finish == PD_FALSE || + signature->content_pos_begin == 0 || + signature->content_pos_end == 0 || + signature->byterange_pos_begin == 0 || + signature->byterange_pos_end == 0) { return; - - length1 = (pduint32)(contents - signature->data->buffer + 10); - - pduint8* p = signature->data->buffer + length1; - offset2 = length1; - while (*p != '>') { - ++offset2; - ++p; } - - offset2 += 1; - length2 = signature->data->written - offset2; - - p = find_string_in_binary(signature->data->buffer, signature->data->written, "/ByteRange ["); - if (!p) + if (fopen_s(&fd, signature->pdf_file, "rb+")) { return; - - sprintf((char*) (p + 12), "%d %d %d %d", offset1, length1, offset2, length2); - - p += 12; - while (*p != '\0') { - ++p; } - *p = ' '; - while (*p != ']') { - *p = ' '; - ++p; + ranges[0].offset = 0; + ranges[0].len = signature->content_pos_begin; + ranges[1].offset = signature->content_pos_end; + + fseek(fd, 0, SEEK_END); + ranges[1].len = ftell(fd) - signature->content_pos_end; + snprintf(byterange_value, sizeof(byterange_value), " %d %d %d %d", + ranges[0].offset, + ranges[0].len, + ranges[1].offset, + ranges[1].len); + byterange_len = signature->byterange_pos_end - signature->byterange_pos_begin - strlen(byterange_value) - 2; + fseek(fd, signature->byterange_pos_begin + 1, SEEK_SET); + fputs(byterange_value, fd); + while (byterange_len--) { + fputc(' ', fd); } - - pduint8* buffer_to_sign = (pduint8*)pd_alloc(signature->pool, sizeof(pduint8) * (length1 + length2)); - memcpy(buffer_to_sign, signature->data->buffer + offset1, length1); - memcpy(buffer_to_sign + length1, signature->data->buffer + offset2, length2); - - pduint32 signed_len_in_hex = offset2 - length1 - 2; - pduint32 signed_len_in_bytes = 0; - pduint8* signed_data = (pduint8*)pd_alloc(signature->pool, sizeof(pduint8) * signed_len_in_hex); - pduint8* signed_data_hex = (pduint8*)pd_alloc(signature->pool, sizeof(pduint8) * (signed_len_in_hex + 1)); - memset(signed_data, 0, sizeof(pduint8) * signed_len_in_hex); - memset(signed_data_hex, 0, sizeof(pduint8) * (signed_len_in_hex + 1)); - - signed_len_in_bytes = pdfr_digsig_sign_data(signature->ds, buffer_to_sign, length1 + length2, signed_data, signed_len_in_hex); - if (signed_len_in_bytes > 0) { - pduint32 i; - // converting to hex - for (i = 0; i < signed_len_in_bytes; ++i) { - sprintf((char*)&signed_data_hex[i * 2], "%02X", signed_data[i]); - } - - p = signature->data->buffer + offset1 + length1 + 1; - sprintf((char*)p, "%s", signed_data_hex); - while (*p != '\0') { - ++p; - } - *p = '0'; - while (*p != '>') { - *p = '0'; - ++p; + fflush(fd); + content_len = (signature->content_pos_end - signature->content_pos_begin) / 2; + content_value = (pduint8*)pd_alloc(signature->pool, content_len); + if (content_value) { + signature_len = pdfr_digsig_sign_range(signature->ds, fd, ranges, sizeof(ranges) / sizeof(t_sign_range), content_value, content_len); + if (signature_len > 0) { + fseek(fd, signature->content_pos_begin + 1, SEEK_SET); + for (int i = 0; i < signature_len; i++) { + fprintf(fd, "%02X", content_value[i]); + } } + pd_free(content_value); } - - pd_free(buffer_to_sign); - - signature->userWriter(signature->data->buffer, 0, signature->data->written, signature->userCookie); + fflush(fd); + fclose(fd); } // Destroy void digitalsignature_destroy(t_pdfdigitalsignature* signature) { assert(signature); - + + // sign document + digitalsignature_finish(signature); pdfr_exit_digitalsignature(signature->ds); - // restore user defined write callback and cookie - pdfr_encoder_set_outputwriter(signature->encoder, signature->userWriter); - pdfr_encoder_set_cookie(signature->encoder, signature->userCookie); - // free allocated memmory if (signature->name != NULL) pd_free(signature->name); @@ -217,9 +177,8 @@ void digitalsignature_destroy(t_pdfdigitalsignature* signature) { pd_free(signature->reason); if (signature->contact_info != NULL) pd_free(signature->contact_info); - if (signature->data->buffer != NULL) - pd_free(signature->data->buffer); - + if (signature->pdf_file != NULL) + pd_free(signature->pdf_file); pd_free(signature); signature = NULL; @@ -297,41 +256,12 @@ void digitalsignature_set_page(t_pdfdigitalsignature* signature, t_pdvalue page) signature->page = page; } -// callback for writing data during digital signing -int digitalsignature_writer(const pduint8* data, pduint32 offset, pduint32 len, void* cookie) { - assert(cookie); - - if (!data || !len) - return 0; - - data += offset; - - t_pdfdigitalsignature* digitalSignature = (t_pdfdigitalsignature*) cookie; - - if ((digitalSignature->data->written + len) > digitalSignature->data->bufferSize) { - pduint32 size = digitalSignature->data->written + len; - pduint8* buf = (pduint8*)pd_alloc(digitalSignature->pool, sizeof(pduint8) * size); - - if (!buf) - return 0; - - memcpy(buf, digitalSignature->data->buffer, digitalSignature->data->written); - pd_free(digitalSignature->data->buffer); - digitalSignature->data->buffer = buf; - digitalSignature->data->bufferSize = size; - } - - memcpy(digitalSignature->data->buffer + digitalSignature->data->written, data, len); - digitalSignature->data->written += len; - - return len; -} - // Creates necessary dictionaries for signature void digitalsignature_create_dictionaries(t_pdfdigitalsignature* signature) { pdbool succ; t_pdvalue* catalog = pdfr_encoder_catalog(signature->encoder); t_pdxref* xref = pdfr_encoder_xref(signature->encoder); + pduint8* content; // Create AcroForm entry in the Catalog t_pdvalue acro_form = pd_dict_get(*catalog, (t_pdatom)"AcroForm", &succ); @@ -384,14 +314,15 @@ void digitalsignature_create_dictionaries(t_pdfdigitalsignature* signature) { } // Preparing /V dictionary - char content[1024]; - memset(content, '0', 1024); - + t_pdvalue v_dict = pd_dict_new(signature->pool, 3); // calculating lenght of the Content just to have accurate size pdint32 signature_length = pdfr_digsig_signature_length(signature->ds); - - t_pdvalue v_dict = pd_dict_new(signature->pool, 3); - pd_dict_put(v_dict, ((t_pdatom)"Contents"), pdstringvalue(pd_string_new_binary(signature->pool, signature_length, content))); + content = (pduint8 *)pd_alloc(signature->pool, signature_length); + if (content != NULL) { + memset(content, '\0', signature_length); + pd_dict_put(v_dict, ((t_pdatom)"Contents"), pdstringvalue(pd_string_new_binary(signature->pool, signature_length, content))); + pd_free(content); + } pd_dict_put(v_dict, ((t_pdatom)"Type"), pdatomvalue((t_pdatom)"Sig")); pd_dict_put(v_dict, ((t_pdatom)"Filter"), pdatomvalue((t_pdatom)"Adobe.PPKLite")); pd_dict_put(v_dict, ((t_pdatom)"SubFilter"), pdatomvalue((t_pdatom)"adbe.pkcs7.detached")); @@ -436,3 +367,17 @@ pduint32 pd_digitalsignature_digsig_objnum(t_pdfdigitalsignature* signature) { return signature->digsig_objnum; } + +void pd_digitalsignature_setcontent_pos(t_pdfdigitalsignature* signature, pduint32 content_pos_begin, pduint32 content_pos_end) { + assert(signature); + + signature->content_pos_begin = content_pos_begin; + signature->content_pos_end = content_pos_end; +} + +void pd_digitalsignature_setbyterange_pos(t_pdfdigitalsignature* signature, pduint32 byterange_pos_begin, pduint32 byterange_pos_end) { + assert(signature); + + signature->byterange_pos_begin = byterange_pos_begin; + signature->byterange_pos_end = byterange_pos_end; +} diff --git a/pdfras_writer/PdfDigitalSignature.h b/pdfras_writer/PdfDigitalSignature.h index 5332304..38f6e62 100644 --- a/pdfras_writer/PdfDigitalSignature.h +++ b/pdfras_writer/PdfDigitalSignature.h @@ -15,7 +15,10 @@ extern "C" { // encoder - t_pdfrasencoder // pfx_file - pfx file with certificate // password - password for certificate -t_pdfdigitalsignature* digitalsignature_create(t_pdfrasencoder* encoder, const char* pfx_file, const char* password); +t_pdfdigitalsignature* digitalsignature_create(t_pdfrasencoder* encoder, const char *pdf_file, const char* pfx_file, const char* password); + +// mark signature as ready +void digitalsignature_ready(t_pdfdigitalsignature* signature); // finish process of signing void digitalsignature_finish(t_pdfdigitalsignature* signature); @@ -38,6 +41,12 @@ int digitalsignature_writer(const pduint8* data, pduint32 offset, pduint32 len, // get digital signature dictionary object number extern pduint32 pd_digitalsignature_digsig_objnum(t_pdfdigitalsignature* signature); +// save content position from stream +extern void pd_digitalsignature_setcontent_pos(t_pdfdigitalsignature* signature, pduint32 content_pos_begin, pduint32 content_pos_end); + +// save byterange position from stream +void pd_digitalsignature_setbyterange_pos(t_pdfdigitalsignature* signature, pduint32 byterange_pos_begin, pduint32 byterange_pos_end); + #ifdef __cplusplus } #endif diff --git a/pdfras_writer/PdfRaster.c b/pdfras_writer/PdfRaster.c index aa84c9f..8cc50fa 100644 --- a/pdfras_writer/PdfRaster.c +++ b/pdfras_writer/PdfRaster.c @@ -138,12 +138,12 @@ t_pdfrasencoder* pdfr_encoder_create(int apiLevel, t_OS *os) return enc; } -t_pdfrasencoder* pdfr_signed_encoder_create(int apiLevel, t_OS* os, const char* pfx_file, const char* password) { +t_pdfrasencoder* pdfr_signed_encoder_create(int apiLevel, t_OS* os, const char *pdf_file, const char* pfx_file, const char* password) { t_pdfrasencoder* enc = create_encoder(apiLevel, os); if (!enc) return NULL; - enc->signer = digitalsignature_create(enc, pfx_file, password); + enc->signer = digitalsignature_create(enc, pdf_file, pfx_file, password); if (!enc->signer) { pdfr_encoder_destroy(enc); return NULL; @@ -626,9 +626,9 @@ void pdfr_encoder_end_document(t_pdfrasencoder* enc) pd_outstream_set_event_handler(stm, PDF_EVENT_BEFORE_STARTXREF, pdfr_sig_handler, NULL); pd_write_endofdocument(stm, enc->xref, enc->catalog, enc->info, enc->trailer); - // sign document if was set to sign - if (enc->signer) - digitalsignature_finish(enc->signer); + // mark signature as ready (before call digitalsignature_finish method) + if (enc->signer) + digitalsignature_ready(enc->signer); // Note: we leave all the final data structures intact in case the client // has questions, like 'how many pages did we write?' or 'how big was the output file?'. diff --git a/pdfras_writer/PdfRaster.h b/pdfras_writer/PdfRaster.h index 818517c..3d27350 100644 --- a/pdfras_writer/PdfRaster.h +++ b/pdfras_writer/PdfRaster.h @@ -81,7 +81,7 @@ typedef t_pdfrasencoder* (PDFRASAPICALL *pfn_pdfr_encoder_create)(int apiLevel, // Extended params: // pfx_file: path to the certificate stored in PFX file // password: password for certificate -t_pdfrasencoder* PDFRASAPICALL pdfr_signed_encoder_create(int apiLevel, t_OS* os, const char* pfx_file, const char* password); +t_pdfrasencoder* PDFRASAPICALL pdfr_signed_encoder_create(int apiLevel, t_OS* os, const char *pdf_file, const char* pfx_file, const char* password); typedef t_pdfrasencoder* (PDFRASAPICALL *pfn_signed_encoder_create) (int apiLevel, t_OS* os, const char* pfx_file, const char* password); // Query function for t_pdfrasencoder diff --git a/pdfras_writer/PdfStreaming.c b/pdfras_writer/PdfStreaming.c index 4f7127f..58287e5 100644 --- a/pdfras_writer/PdfStreaming.c +++ b/pdfras_writer/PdfStreaming.c @@ -20,6 +20,7 @@ struct t_pdoutstream { void *writercookie; pduint32 pos; + pduint32 current_obj; fOutStreamEventHandler eventHandler[PDF_OUTPUT_EVENT_COUNT]; void* eventCookie[PDF_OUTPUT_EVENT_COUNT]; }; @@ -235,30 +236,41 @@ static pdbool itemwriter(t_pdatom key, t_pdvalue value, void *cookie) writeatom(os, key); pd_putc(os, ' '); - // Don't encrypt /Contents from digital signature dictionary - pduint32 digsig_objnum = 0; - pduint32 current_objnum = 0; - if (os->signature) - digsig_objnum = pd_digitalsignature_digsig_objnum(os->signature); - - if (os->encrypter) - current_objnum = pd_encrypt_get_current_objectnumber(os->encrypter); - - pdbool digsig_contents = PD_FALSE; - if (digsig_objnum == current_objnum) { + // Don't encrypt /Contents from digital signature dictionary + pdbool disable_encrypt_value = PD_FALSE; + pduint32 content_pos_begin = 0, byterange_pos_begin = 0; + + if (os->signature) { + pduint32 digsig_objnum = pd_digitalsignature_digsig_objnum(os->signature); + pduint32 enc_objnum = os->encrypter? pd_encrypt_get_current_objectnumber(os->encrypter) : 0; + const char* key_name = pd_atom_name(key); if (strcmp(key_name, "Contents") == 0) { - digsig_contents = PD_TRUE; - } + disable_encrypt_value = enc_objnum != 0 && digsig_objnum == enc_objnum; + if (os->current_obj != 0 && os->current_obj == digsig_objnum) { + content_pos_begin = pd_outstream_pos(os); + } + } + else if (strcmp(key_name, "ByteRange") == 0) { + if (os->current_obj != 0 && os->current_obj == digsig_objnum) { + byterange_pos_begin = pd_outstream_pos(os); + } + } } - if (digsig_contents == PD_TRUE) - pd_encrypt_deactivate(os->encrypter); + if (disable_encrypt_value == PD_TRUE) + pd_encrypt_deactivate(os->encrypter); pd_write_value(os, value); - - if (digsig_contents == PD_TRUE) - pd_encrypt_activate(os->encrypter); + if (content_pos_begin > 0) { + pd_digitalsignature_setcontent_pos(os->signature, content_pos_begin, pd_outstream_pos(os)); + } + else if (byterange_pos_begin > 0) { + pd_digitalsignature_setbyterange_pos(os->signature, byterange_pos_begin, pd_outstream_pos(os)); + } + if (disable_encrypt_value == PD_TRUE) { + pd_encrypt_activate(os->encrypter); + } return PD_TRUE; } @@ -488,7 +500,9 @@ void pd_write_reference_declaration(t_pdoutstream *stm, t_pdvalue ref) if (pd_stream_is_encrypted(stm) && pd_encrypt_is_active(stm->encrypter)) { pd_encrypt_start_object(stm->encrypter, onr, 0); } + stm->current_obj = onr; pd_write_value(stm, pd_reference_get_value(ref)); + stm->current_obj = 0; pd_puts(stm, "\nendobj\n"); pd_reference_mark_written(ref); } diff --git a/pdfras_writer_managed/PdfRasterWriter.cpp b/pdfras_writer_managed/PdfRasterWriter.cpp index c80ffa9..2973a82 100644 --- a/pdfras_writer_managed/PdfRasterWriter.cpp +++ b/pdfras_writer_managed/PdfRasterWriter.cpp @@ -136,7 +136,8 @@ static void checkStateValid(int idx) } namespace PdfRasterWriter { - int Writer::encoder_create(int apiLevel, String^ pdfFileName) + + int Writer::file_open(int apiLevel, String^ pdfFileName, String^ mode) { LOG(fprintf(fp, "> apiLevel=%d", apiLevel)); @@ -152,9 +153,10 @@ namespace PdfRasterWriter { } pin_ptr wfile = PtrToStringChars(pdfFileName); - LOG(fprintf(fp, "- pdfFileName=\"%S\"", wfile)); + pin_ptr wmode = PtrToStringChars(mode); + LOG(fprintf(fp, "- pdfFileName=\"%S\" \"%S\"", wfile, wmode)); - if (errno_t err = _wfopen_s((FILE **)&state[idx].os.writeoutcookie, wfile, L"wb")) { + if (errno_t err = _wfopen_s((FILE **)&state[idx].os.writeoutcookie, wfile, wmode)) { state[idx].os.writeoutcookie = nullptr; state[idx].invalidate(); char buf[256]; buf[0] = 0; strerror_s(buf, sizeof(buf) - 1, err); @@ -162,6 +164,13 @@ namespace PdfRasterWriter { throw(L"_wfopen_s() returned 0 "); } + return idx; + } + + int Writer::encoder_create(int apiLevel, String^ pdfFileName) + { + int idx = file_open(apiLevel, pdfFileName, "wb"); + state[idx].enc = pdfr_encoder_create(apiLevel, &state[idx].os); if (!state[idx].valid()) { state[idx].invalidate(); @@ -175,36 +184,15 @@ namespace PdfRasterWriter { int Writer::encoder_create_digitally_signed(int apiLevel, String^ pdfFileName, String^ pfxFile, String^ password) { - LOG(fprintf(fp, "> apiLevel=%d", apiLevel)); - - int idx; - for (idx = 0; idx < MAX_ENCODERS; ++idx) { - if (!state[idx].valid()) { - break; // good, found an unused encoder struct - } - } - - if (idx == MAX_ENCODERS) { - LOG(fprintf(fp, "- ERROR: too many encoders used")); - throw(L"too many encoder used"); - } - - pin_ptr wfile = PtrToStringChars(pdfFileName); - LOG(fprintf(fp, "- pdfFileName=\"%S\"", wfile)); - - if (errno_t err = _wfopen_s((FILE **)&state[idx].os.writeoutcookie, wfile, L"wb")) { - state[idx].os.writeoutcookie = nullptr; - state[idx].invalidate(); - char buf[256]; buf[0] = 0; strerror_s(buf, sizeof(buf) - 1, err); - LOG(fprintf(fp, "- ERROR: _wfopen_s() returned 0 errno=%d \"%s\"", err, buf)); - throw(L"_wfopen_s() returned 0"); - } + int idx = file_open(apiLevel, pdfFileName, "wb"); const char* pfx_file = (const char*)(Marshal::StringToHGlobalAnsi(pfxFile)).ToPointer(); const char* pfx_passwd = (const char*)(Marshal::StringToHGlobalAnsi(password)).ToPointer(); + const char* pdf_file = (const char*)(Marshal::StringToHGlobalAnsi(pdfFileName)).ToPointer(); - state[idx].enc = pdfr_signed_encoder_create(apiLevel, &state[idx].os, pfx_file, pfx_passwd); + state[idx].enc = pdfr_signed_encoder_create(apiLevel, &state[idx].os, pdf_file, pfx_file, pfx_passwd); + Marshal::FreeHGlobal(IntPtr((void*)pdf_file)); Marshal::FreeHGlobal(IntPtr((void*)pfx_file)); Marshal::FreeHGlobal(IntPtr((void*)pfx_passwd)); diff --git a/pdfras_writer_managed/PdfRasterWriter.h b/pdfras_writer_managed/PdfRasterWriter.h index cb35e40..ed97a4b 100644 --- a/pdfras_writer_managed/PdfRasterWriter.h +++ b/pdfras_writer_managed/PdfRasterWriter.h @@ -89,7 +89,8 @@ namespace PdfRasterWriter { void digital_signature_set_location(int enc, String^ location); void digital_signature_set_contactinfo(int enc, String^ contact); void encoder_destroy(int enc); - + private: + int file_open(int apiLevel, String^ pdfFileName, String^ mode); #pragma endregion Public Methods for PdfRasterWriter }; }