summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorPaul Gardiner <paul.gardiner@artifex.com>2018-01-04 15:11:24 +0000
committerPaul Gardiner <paul.gardiner@artifex.com>2018-01-19 13:52:25 +0000
commitbcce8e5dc38509c5aa43174a0d6e0341444f1d87 (patch)
tree27bcd71231a322ad83fb7e83ff56d02e458f3ee6 /source
parent457873fbf7fd6d40242722f3a51b41428302d0ca (diff)
downloadmupdf-bcce8e5dc38509c5aa43174a0d6e0341444f1d87.tar.xz
Perform document signing via fz_stream and fz_output
This change achieves two goals. It allows signing to be performed even when the document is obtained other than from a disk file. It also reestablishes to a working state signing of file-based documents, a feature that was broken due to complete_signatures being called after certain tables, avaialble via the output options object, had been destroyed.
Diffstat (limited to 'source')
-rw-r--r--source/pdf/pdf-pkcs7.c112
-rw-r--r--source/pdf/pdf-write.c138
2 files changed, 171 insertions, 79 deletions
diff --git a/source/pdf/pdf-pkcs7.c b/source/pdf/pdf-pkcs7.c
index 7139156f..864e3039 100644
--- a/source/pdf/pdf-pkcs7.c
+++ b/source/pdf/pdf-pkcs7.c
@@ -80,6 +80,92 @@ static const char AdobeCA_p7c[] = {
#warning detect version of openssl at compile time
#endif
+typedef struct
+{
+ fz_context *ctx;
+ fz_stream *stm;
+} BIO_stream_data;
+
+static int stream_read(BIO *b, char *buf, int size)
+{
+ BIO_stream_data *data = (BIO_stream_data *)BIO_get_data(b);
+ return fz_read(data->ctx, data->stm, buf, size);
+}
+
+static long stream_ctrl(BIO *b, int cmd, long arg1, void *arg2)
+{
+ BIO_stream_data *data = (BIO_stream_data *)BIO_get_data(b);
+ switch (cmd)
+ {
+ case BIO_C_FILE_SEEK:
+ fz_seek(data->ctx, data->stm, arg1, SEEK_SET);
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+static int stream_new(BIO *b)
+{
+ BIO_stream_data *data = (BIO_stream_data *)malloc(sizeof(BIO_stream_data));
+ if (!data)
+ return 0;
+
+ data->ctx = NULL;
+ data->stm = NULL;
+
+ BIO_set_init(b, 1);
+ BIO_set_data(b, data);
+ BIO_clear_flags(b, INT_MAX);
+
+ return 1;
+}
+
+static int stream_free(BIO *b)
+{
+ if (b == NULL)
+ return 0;
+
+ free(BIO_get_data(b));
+ BIO_set_data(b, NULL);
+ BIO_set_init(b, 0);
+ BIO_clear_flags(b, INT_MAX);
+
+ return 1;
+}
+
+static long stream_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
+{
+ return 1;
+}
+
+static BIO *BIO_new_stream(fz_context *ctx, fz_stream *stm)
+{
+ static BIO_METHOD *methods = NULL;
+ BIO *bio;
+ BIO_stream_data *data;
+
+ if (!methods)
+ {
+ methods = BIO_meth_new(BIO_TYPE_NONE, "segment reader");
+ if (!methods)
+ return NULL;
+
+ BIO_meth_set_read(methods, stream_read);
+ BIO_meth_set_ctrl(methods, stream_ctrl);
+ BIO_meth_set_create(methods, stream_new);
+ BIO_meth_set_destroy(methods, stream_free);
+ BIO_meth_set_callback_ctrl(methods, stream_callback_ctrl);
+ }
+
+ bio = BIO_new(methods);
+ data = BIO_get_data(bio);
+ data->ctx = ctx;
+ data->stm = stm;
+
+ return bio;
+}
+
enum
{
SEG_START = 0,
@@ -649,25 +735,25 @@ pdf_designated_name *pdf_signer_designated_name(fz_context *ctx, pdf_signer *sig
return (pdf_designated_name *)dn;
}
-void pdf_write_digest(fz_context *ctx, pdf_document *doc, const char *filename, pdf_obj *byte_range, int digest_offset, int digest_length, pdf_signer *signer)
+void pdf_write_digest(fz_context *ctx, fz_output *out, pdf_obj *byte_range, int digest_offset, int digest_length, pdf_signer *signer)
{
+ fz_stream *in = NULL;
BIO *bdata = NULL;
BIO *bsegs = NULL;
BIO *bp7in = NULL;
BIO *bp7 = NULL;
PKCS7 *p7 = NULL;
PKCS7_SIGNER_INFO *si;
- FILE *f = NULL;
int (*brange)[2] = NULL;
int brange_len = pdf_array_len(ctx, byte_range)/2;
+ fz_var(in);
fz_var(bdata);
fz_var(bsegs);
fz_var(bp7in);
fz_var(bp7);
fz_var(p7);
- fz_var(f);
fz_try(ctx)
{
@@ -675,6 +761,8 @@ void pdf_write_digest(fz_context *ctx, pdf_document *doc, const char *filename,
int p7_len;
int i;
+ in = fz_stream_from_output(ctx, out);
+
brange = fz_calloc(ctx, brange_len, sizeof(*brange));
for (i = 0; i < brange_len; i++)
{
@@ -682,10 +770,9 @@ void pdf_write_digest(fz_context *ctx, pdf_document *doc, const char *filename,
brange[i][1] = pdf_to_int(ctx, pdf_array_get(ctx, byte_range, 2*i+1));
}
- bdata = BIO_new(BIO_s_file());
+ bdata = BIO_new_stream(ctx, in);
if (bdata == NULL)
fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to create file BIO");
- BIO_read_filename(bdata, filename);
bsegs = BIO_new(BIO_f_segments());
if (bsegs == NULL)
@@ -729,6 +816,8 @@ void pdf_write_digest(fz_context *ctx, pdf_document *doc, const char *filename,
bsegs = NULL;
BIO_free(bdata);
bdata = NULL;
+ fz_drop_stream(ctx, in);
+ in = NULL;
bp7 = BIO_new(BIO_s_mem());
if (bp7 == NULL || !i2d_PKCS7_bio(bp7, p7))
@@ -738,24 +827,19 @@ void pdf_write_digest(fz_context *ctx, pdf_document *doc, const char *filename,
if (p7_len*2 + 2 > digest_length)
fz_throw(ctx, FZ_ERROR_GENERIC, "Insufficient space for digest");
- f = fopen(filename, "rb+");
- if (f == NULL)
- fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to write digest");
-
- fseek(f, digest_offset+1, SEEK_SET);
+ fz_seek_output(ctx, out, digest_offset+1, SEEK_SET);
for (i = 0; i < p7_len; i++)
- fprintf(f, "%02x", p7_ptr[i]);
+ fz_write_printf(ctx, out, "%02x", p7_ptr[i]);
}
fz_always(ctx)
{
+ fz_drop_stream(ctx, in);
PKCS7_free(p7);
BIO_free(bsegs);
BIO_free(bdata);
BIO_free(bp7in);
BIO_free(bp7);
- if (f)
- fclose(f);
}
fz_catch(ctx)
{
@@ -896,7 +980,7 @@ void pdf_drop_signer(fz_context *ctx, pdf_signer *signer)
{
}
-void pdf_write_digest(fz_context *ctx, pdf_document *doc, const char *filename, pdf_obj *byte_range, int digest_offset, int digest_length, pdf_signer *signer)
+void pdf_write_digest(fz_context *ctx, fz_output *out, pdf_obj *byte_range, int digest_offset, int digest_length, pdf_signer *signer)
{
}
diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c
index b13970b9..28a505f9 100644
--- a/source/pdf/pdf-write.c
+++ b/source/pdf/pdf-write.c
@@ -2624,95 +2624,102 @@ static void presize_unsaved_signature_byteranges(fz_context *ctx, pdf_document *
}
}
-static void complete_signatures(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, const char *filename)
+static void complete_signatures(fz_context *ctx, pdf_document *doc, pdf_write_state *opts)
{
pdf_unsaved_sig *usig;
char buf[5120];
int s;
int i;
int last_end;
- FILE *f;
+ fz_stream *stm = NULL;
+ fz_var(stm);
- for (s = 0; s < doc->num_incremental_sections; s++)
+ fz_try(ctx)
{
- pdf_xref *xref = &doc->xref_sections[doc->num_incremental_sections - s - 1];
-
- if (xref->unsaved_sigs)
+ for (s = 0; s < doc->num_incremental_sections; s++)
{
- pdf_obj *byte_range;
+ pdf_xref *xref = &doc->xref_sections[doc->num_incremental_sections - s - 1];
- f = fopen(filename, "rb+");
- if (!f)
- fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to open %s to complete signatures", filename);
-
- /* Locate the byte ranges and contents in the saved file */
- for (usig = xref->unsaved_sigs; usig; usig = usig->next)
+ if (xref->unsaved_sigs)
{
- char *bstr, *cstr, *fstr;
- int pnum = pdf_obj_parent_num(ctx, pdf_dict_getl(ctx, usig->field, PDF_NAME_V, PDF_NAME_ByteRange, NULL));
- fseek(f, opts->ofs_list[pnum], SEEK_SET);
- (void)fread(buf, 1, sizeof(buf), f);
- buf[sizeof(buf)-1] = 0;
+ pdf_obj *byte_range;
- bstr = strstr(buf, "/ByteRange");
- cstr = strstr(buf, "/Contents");
- fstr = strstr(buf, "/Filter");
-
- if (bstr && cstr && fstr && bstr < cstr && cstr < fstr)
+ stm = fz_stream_from_output(ctx, opts->out);
+ /* Locate the byte ranges and contents in the saved file */
+ for (usig = xref->unsaved_sigs; usig; usig = usig->next)
{
- usig->byte_range_start = bstr - buf + 10 + opts->ofs_list[pnum];
- usig->byte_range_end = cstr - buf + opts->ofs_list[pnum];
- usig->contents_start = cstr - buf + 9 + opts->ofs_list[pnum];
- usig->contents_end = fstr - buf + opts->ofs_list[pnum];
+ char *bstr, *cstr, *fstr;
+ int pnum = pdf_obj_parent_num(ctx, pdf_dict_getl(ctx, usig->field, PDF_NAME_V, PDF_NAME_ByteRange, NULL));
+ fz_seek(ctx, stm, opts->ofs_list[pnum], SEEK_SET);
+ (void)fz_read(ctx, stm, (unsigned char *)buf, sizeof(buf));
+ buf[sizeof(buf)-1] = 0;
+
+ bstr = strstr(buf, "/ByteRange");
+ cstr = strstr(buf, "/Contents");
+ fstr = strstr(buf, "/Filter");
+
+ if (bstr && cstr && fstr && bstr < cstr && cstr < fstr)
+ {
+ usig->byte_range_start = bstr - buf + 10 + opts->ofs_list[pnum];
+ usig->byte_range_end = cstr - buf + opts->ofs_list[pnum];
+ usig->contents_start = cstr - buf + 9 + opts->ofs_list[pnum];
+ usig->contents_end = fstr - buf + opts->ofs_list[pnum];
+ }
}
- }
- /* Recreate ByteRange with correct values. Initially store the
- * recreated object in the first of the unsaved signatures */
- byte_range = pdf_new_array(ctx, doc, 4);
- pdf_dict_putl_drop(ctx, xref->unsaved_sigs->field, byte_range, PDF_NAME_V, PDF_NAME_ByteRange, NULL);
+ fz_drop_stream(ctx, stm);
+ stm = NULL;
- last_end = 0;
- for (usig = xref->unsaved_sigs; usig; usig = usig->next)
- {
- pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, last_end));
- pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, usig->contents_start - last_end));
- last_end = usig->contents_end;
- }
- pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, last_end));
- pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, xref->end_ofs - last_end));
+ /* Recreate ByteRange with correct values. Initially store the
+ * recreated object in the first of the unsaved signatures */
+ byte_range = pdf_new_array(ctx, doc, 4);
+ pdf_dict_putl_drop(ctx, xref->unsaved_sigs->field, byte_range, PDF_NAME_V, PDF_NAME_ByteRange, NULL);
- /* Copy the new ByteRange to the other unsaved signatures */
- for (usig = xref->unsaved_sigs->next; usig; usig = usig->next)
- pdf_dict_putl_drop(ctx, usig->field, pdf_copy_array(ctx, byte_range), PDF_NAME_V, PDF_NAME_ByteRange, NULL);
+ last_end = 0;
+ for (usig = xref->unsaved_sigs; usig; usig = usig->next)
+ {
+ pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, last_end));
+ pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, usig->contents_start - last_end));
+ last_end = usig->contents_end;
+ }
+ pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, last_end));
+ pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, xref->end_ofs - last_end));
- /* Write the byte range into buf, padding with spaces*/
- i = pdf_sprint_obj(ctx, buf, sizeof(buf), byte_range, 1);
- memset(buf+i, ' ', sizeof(buf)-i);
+ /* Copy the new ByteRange to the other unsaved signatures */
+ for (usig = xref->unsaved_sigs->next; usig; usig = usig->next)
+ pdf_dict_putl_drop(ctx, usig->field, pdf_copy_array(ctx, byte_range), PDF_NAME_V, PDF_NAME_ByteRange, NULL);
- /* Write the byte range to the file */
- for (usig = xref->unsaved_sigs; usig; usig = usig->next)
- {
- fseek(f, usig->byte_range_start, SEEK_SET);
- fwrite(buf, 1, usig->byte_range_end - usig->byte_range_start, f);
- }
+ /* Write the byte range into buf, padding with spaces*/
+ i = pdf_sprint_obj(ctx, buf, sizeof(buf), byte_range, 1);
+ memset(buf+i, ' ', sizeof(buf)-i);
- fclose(f);
+ /* Write the byte range to the file */
+ for (usig = xref->unsaved_sigs; usig; usig = usig->next)
+ {
+ fz_seek_output(ctx, opts->out, usig->byte_range_start, SEEK_SET);
+ fz_write_data(ctx, opts->out, buf, usig->byte_range_end - usig->byte_range_start);
+ }
- /* Write the digests into the file */
- for (usig = xref->unsaved_sigs; usig; usig = usig->next)
- pdf_write_digest(ctx, doc, filename, byte_range, usig->contents_start, usig->contents_end - usig->contents_start, usig->signer);
+ /* Write the digests into the file */
+ for (usig = xref->unsaved_sigs; usig; usig = usig->next)
+ pdf_write_digest(ctx, opts->out, byte_range, usig->contents_start, usig->contents_end - usig->contents_start, usig->signer);
- /* delete the unsaved_sigs records */
- while ((usig = xref->unsaved_sigs) != NULL)
- {
- xref->unsaved_sigs = usig->next;
- pdf_drop_obj(ctx, usig->field);
- pdf_drop_signer(ctx, usig->signer);
- fz_free(ctx, usig);
+ /* delete the unsaved_sigs records */
+ while ((usig = xref->unsaved_sigs) != NULL)
+ {
+ xref->unsaved_sigs = usig->next;
+ pdf_drop_obj(ctx, usig->field);
+ pdf_drop_signer(ctx, usig->signer);
+ fz_free(ctx, usig);
+ }
}
}
}
+ fz_catch(ctx)
+ {
+ fz_drop_stream(ctx, stm);
+ fz_rethrow(ctx);
+ }
}
static void clean_content_streams(fz_context *ctx, pdf_document *doc, int sanitize, int ascii)
@@ -3054,6 +3061,8 @@ do_pdf_save_document(fz_context *ctx, pdf_document *doc, pdf_write_state *opts,
doc->xref_sections[0].end_ofs = fz_tell_output(ctx, opts->out);
}
+ complete_signatures(ctx, doc, opts);
+
doc->dirty = 0;
}
fz_always(ctx)
@@ -3149,7 +3158,6 @@ void pdf_save_document(fz_context *ctx, pdf_document *doc, const char *filename,
{
do_pdf_save_document(ctx, doc, &opts, in_opts);
fz_close_output(ctx, opts.out);
- complete_signatures(ctx, doc, &opts, filename);
}
fz_always(ctx)
{