summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/pdf/pdf-appearance.c24
-rw-r--r--source/pdf/pdf-form.c51
-rw-r--r--source/pdf/pdf-object.c7
-rw-r--r--source/pdf/pdf-pkcs7.c392
-rw-r--r--source/pdf/pdf-write.c119
-rw-r--r--source/pdf/pdf-xref.c11
6 files changed, 590 insertions, 14 deletions
diff --git a/source/pdf/pdf-appearance.c b/source/pdf/pdf-appearance.c
index e91b699e..968a6d9b 100644
--- a/source/pdf/pdf-appearance.c
+++ b/source/pdf/pdf-appearance.c
@@ -1679,7 +1679,6 @@ static fz_text *layout_text(fz_context *ctx, font_info *font_rec, char *str, flo
fz_matrix tm;
fz_font *font = font_rec->font->font;
fz_text *text;
- int mask = FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
fz_scale(&tm, font_rec->da_rec.font_size, font_rec->da_rec.font_size);
text = fz_new_text(ctx, font, &tm, 0);
@@ -1877,7 +1876,7 @@ static void insert_signature_appearance_layers(pdf_document *doc, pdf_annot *ann
{
fz_context *ctx = doc->ctx;
pdf_obj *ap = pdf_dict_getp(annot->obj, "AP/N");
- pdf_obj *main = NULL;
+ pdf_obj *main_ap = NULL;
pdf_obj *frm = NULL;
pdf_obj *n0 = NULL;
fz_rect bbox;
@@ -1885,21 +1884,21 @@ static void insert_signature_appearance_layers(pdf_document *doc, pdf_annot *ann
pdf_to_rect(ctx, pdf_dict_gets(ap, "BBox"), &bbox);
- fz_var(main);
+ fz_var(main_ap);
fz_var(frm);
fz_var(n0);
fz_var(fzbuf);
fz_try(ctx)
{
- main = pdf_new_xobject(doc, &bbox, &fz_identity);
+ main_ap = pdf_new_xobject(doc, &bbox, &fz_identity);
frm = pdf_new_xobject(doc, &bbox, &fz_identity);
n0 = pdf_new_xobject(doc, &bbox, &fz_identity);
- pdf_dict_putp(main, "Resources/XObject/FRM", frm);
+ pdf_dict_putp(main_ap, "Resources/XObject/FRM", frm);
fzbuf = fz_new_buffer(ctx, 8);
fz_buffer_printf(ctx, fzbuf, "/FRM Do");
- pdf_update_stream(doc, pdf_to_num(main), fzbuf);
- pdf_dict_puts_drop(main, "Length", pdf_new_int(doc, fzbuf->len));
+ pdf_update_stream(doc, pdf_to_num(main_ap), fzbuf);
+ pdf_dict_puts_drop(main_ap, "Length", pdf_new_int(doc, fzbuf->len));
fz_drop_buffer(ctx, fzbuf);
fzbuf = NULL;
@@ -1919,11 +1918,11 @@ static void insert_signature_appearance_layers(pdf_document *doc, pdf_annot *ann
fz_drop_buffer(ctx, fzbuf);
fzbuf = NULL;
- pdf_dict_putp(annot->obj, "AP/N", main);
+ pdf_dict_putp(annot->obj, "AP/N", main_ap);
}
fz_always(ctx)
{
- pdf_drop_obj(main);
+ pdf_drop_obj(main_ap);
pdf_drop_obj(frm);
pdf_drop_obj(n0);
}
@@ -2000,9 +1999,10 @@ void pdf_set_signature_appearance(pdf_document *doc, pdf_annot *annot, char *nam
/* Display the distinguished name in the right-hand half */
fzbuf = fz_new_buffer(ctx, 256);
- fz_buffer_printf(ctx, fzbuf, "Digitally signed by %s\n", name);
- fz_buffer_printf(ctx, fzbuf, "DN: %s\n", dn);
- fz_buffer_printf(ctx, fzbuf, "Date: %s", date);
+ fz_buffer_printf(ctx, fzbuf, "Digitally signed by %s", name);
+ fz_buffer_printf(ctx, fzbuf, "\nDN: %s", dn);
+ if (date)
+ fz_buffer_printf(ctx, fzbuf, "\nDate: %s", date);
(void)fz_buffer_storage(ctx, fzbuf, &bufstr);
rect = annot->rect;
rect.x0 = (rect.x0 + rect.x1)/2.0f;
diff --git a/source/pdf/pdf-form.c b/source/pdf/pdf-form.c
index 3aa55065..0bf59cc5 100644
--- a/source/pdf/pdf-form.c
+++ b/source/pdf/pdf-form.c
@@ -1551,3 +1551,54 @@ int pdf_signature_widget_contents(pdf_document *doc, pdf_widget *widget, char **
*contents = pdf_to_str_buf(c);
return pdf_to_str_len(c);
}
+
+void pdf_signature_set_value(pdf_document *doc, pdf_obj *field, pdf_signer *signer)
+{
+ fz_context *ctx = doc->ctx;
+ pdf_obj *v;
+ pdf_obj *indv;
+ int vnum;
+ pdf_obj *byte_range;
+ pdf_obj *contents;
+ char buf[2048];
+ pdf_unsaved_sig *unsaved_sig;
+
+ memset(buf, 0, sizeof(buf));
+
+ vnum = pdf_create_object(doc);
+ indv = pdf_new_indirect(doc, vnum, 0);
+ pdf_dict_puts_drop(field, "V", indv);
+
+ fz_var(v);
+ fz_try(ctx)
+ {
+ v = pdf_new_dict(doc, 4);
+ pdf_update_object(doc, vnum, v);
+ }
+ fz_always(ctx)
+ {
+ pdf_drop_obj(v);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+
+ byte_range = pdf_new_array(doc, 4);
+ pdf_dict_puts_drop(v, "ByteRange", byte_range);
+
+ contents = pdf_new_string(doc, buf, sizeof(buf));
+ pdf_dict_puts_drop(v, "Contents", contents);
+
+ pdf_dict_puts_drop(v, "Filter", pdf_new_name(doc, "Adobe.PPKLite"));
+ pdf_dict_puts_drop(v, "SubFilter", pdf_new_name(doc, "adbe.pkcs7.detached"));
+
+ /* Record details within the document structure so that contents
+ * and byte_range can be updated with their correct values at
+ * saving time */
+ unsaved_sig = fz_malloc_struct(doc->ctx, pdf_unsaved_sig);
+ unsaved_sig->field = pdf_keep_obj(field);
+ unsaved_sig->signer = pdf_keep_signer(signer);
+ unsaved_sig->next = doc->unsaved_sigs;
+ doc->unsaved_sigs = unsaved_sig;
+}
diff --git a/source/pdf/pdf-object.c b/source/pdf/pdf-object.c
index 708794ee..704a71df 100644
--- a/source/pdf/pdf-object.c
+++ b/source/pdf/pdf-object.c
@@ -1373,6 +1373,11 @@ pdf_set_obj_parent(pdf_obj *obj, int num)
}
}
+int pdf_obj_parent_num(pdf_obj *obj)
+{
+ return obj->parent_num;
+}
+
pdf_obj *pdf_new_obj_from_str(pdf_document *doc, const char *src)
{
pdf_obj *result;
@@ -1679,7 +1684,7 @@ static void fmt_obj(struct fmt *fmt, pdf_obj *obj)
fmt_puts(fmt, "<unknown object>");
}
-static int
+int
pdf_sprint_obj(char *s, int n, pdf_obj *obj, int tight)
{
struct fmt fmt;
diff --git a/source/pdf/pdf-pkcs7.c b/source/pdf/pdf-pkcs7.c
index 6515abc6..23e8af84 100644
--- a/source/pdf/pdf-pkcs7.c
+++ b/source/pdf/pdf-pkcs7.c
@@ -10,6 +10,7 @@
#include "openssl/objects.h"
#include "openssl/pem.h"
#include "openssl/pkcs7.h"
+#include "openssl/pkcs12.h"
enum
{
@@ -279,6 +280,8 @@ static int verify_sig(char *sig, int sig_len, char *file, int (*byte_range)[2],
goto exit;
bdata = BIO_new(BIO_s_file());
+ if (bdata == NULL)
+ goto exit;
BIO_read_filename(bdata, file);
bsegs = BIO_new(BIO_f_segments());
@@ -339,6 +342,335 @@ exit:
return res;
}
+typedef struct pdf_designated_name_openssl_s
+{
+ pdf_designated_name base;
+ fz_context *ctx;
+ char buf[8192];
+} pdf_designated_name_openssl;
+
+struct pdf_signer_s
+{
+ fz_context *ctx;
+ int refs;
+ X509 *x509;
+ EVP_PKEY *pkey;
+};
+
+void pdf_free_designated_name(pdf_designated_name *dn)
+{
+ if (dn)
+ fz_free(((pdf_designated_name_openssl *)dn)->ctx, dn);
+}
+
+
+static void add_from_bags(X509 **pX509, EVP_PKEY **pPkey, STACK_OF(PKCS12_SAFEBAG) *bags, char *pw);
+
+static void add_from_bag(X509 **pX509, EVP_PKEY **pPkey, PKCS12_SAFEBAG *bag, char *pw)
+{
+ EVP_PKEY *pkey = NULL;
+ X509 *x509 = NULL;
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
+ switch (M_PKCS12_bag_type(bag))
+ {
+ case NID_keyBag:
+ p8 = bag->value.keybag;
+ pkey = EVP_PKCS82PKEY(p8);
+ break;
+
+ case NID_pkcs8ShroudedKeyBag:
+ p8 = PKCS12_decrypt_skey(bag, pw, (int)strlen(pw));
+ if (p8)
+ {
+ pkey = EVP_PKCS82PKEY(p8);
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ }
+ break;
+
+ case NID_certBag:
+ if (M_PKCS12_cert_bag_type(bag) == NID_x509Certificate)
+ x509 = PKCS12_certbag2x509(bag);
+ break;
+
+ case NID_safeContentsBag:
+ add_from_bags(pX509, pPkey, bag->value.safes, pw);
+ break;
+ }
+
+ if (pkey)
+ {
+ if (!*pPkey)
+ *pPkey = pkey;
+ else
+ EVP_PKEY_free(pkey);
+ }
+
+ if (x509)
+ {
+ if (!*pX509)
+ *pX509 = x509;
+ else
+ X509_free(x509);
+ }
+}
+
+static void add_from_bags(X509 **pX509, EVP_PKEY **pPkey, STACK_OF(PKCS12_SAFEBAG) *bags, char *pw)
+{
+ int i;
+
+ for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++)
+ add_from_bag(pX509, pPkey, sk_PKCS12_SAFEBAG_value(bags, i), pw);
+}
+
+pdf_signer *pdf_read_pfx(fz_context *ctx, char *pfile, char *pw)
+{
+ BIO *pfxbio = NULL;
+ PKCS12 *p12 = NULL;
+ STACK_OF(PKCS7) *asafes;
+ pdf_signer *signer = NULL;
+ int i;
+
+ fz_var(pfxbio);
+ fz_var(p12);
+ fz_var(signer);
+ fz_try(ctx)
+ {
+ signer = fz_malloc_struct(ctx, pdf_signer);
+ signer->ctx = ctx;
+ signer->refs = 1;
+
+ OpenSSL_add_all_algorithms();
+
+ EVP_add_digest(EVP_md5());
+ EVP_add_digest(EVP_sha1());
+
+ ERR_load_crypto_strings();
+
+ ERR_clear_error();
+
+ pfxbio = BIO_new_file(pfile, "r");
+ if (pfxbio == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Can't open pfx file: %s", pfile);
+
+ p12 = d2i_PKCS12_bio(pfxbio, NULL);
+ if (p12 == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Invalid pfx file: %s", pfile);
+
+ asafes = PKCS12_unpack_authsafes(p12);
+ if (asafes == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Invalid pfx file: %s", pfile);
+
+ /* Nothing in this for loop can fz_throw */
+ for (i = 0; i < sk_PKCS7_num(asafes); i++)
+ {
+ PKCS7 *p7;
+ STACK_OF(PKCS12_SAFEBAG) *bags;
+ int bagnid;
+
+ p7 = sk_PKCS7_value(asafes, i);
+ bagnid = OBJ_obj2nid(p7->type);
+ switch (bagnid)
+ {
+ case NID_pkcs7_data:
+ bags = PKCS12_unpack_p7data(p7);
+ break;
+ case NID_pkcs7_encrypted:
+ bags = PKCS12_unpack_p7encdata(p7, pw, (int)strlen(pw));
+ break;
+ default:
+ continue;
+ }
+
+ if (bags)
+ {
+ add_from_bags(&signer->x509, &signer->pkey, bags, pw);
+ sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
+ }
+ }
+ sk_PKCS7_pop_free (asafes, PKCS7_free);
+
+ if (signer->pkey == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to obtain public key");
+
+ if (signer->x509 == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to obtain certificate");
+ }
+ fz_always(ctx)
+ {
+ BIO_free(pfxbio);
+ PKCS12_free(p12);
+ }
+ fz_catch(ctx)
+ {
+ pdf_drop_signer(signer);
+ fz_rethrow(ctx);
+ }
+
+ return signer;
+}
+
+pdf_signer *pdf_keep_signer(pdf_signer *signer)
+{
+ if (signer)
+ signer->refs++;
+
+ return signer;
+}
+
+void pdf_drop_signer(pdf_signer *signer)
+{
+ if (signer)
+ {
+ if (--signer->refs == 0)
+ {
+ X509_free(signer->x509);
+ EVP_PKEY_free(signer->pkey);
+ fz_free(signer->ctx, signer);
+ }
+ }
+}
+
+pdf_designated_name *pdf_signer_designated_name(pdf_signer *signer)
+{
+ fz_context *ctx = signer->ctx;
+ pdf_designated_name_openssl *dn = fz_malloc_struct(ctx, pdf_designated_name_openssl);
+ char *p;
+
+ dn->ctx = ctx;
+ X509_NAME_oneline(X509_get_subject_name(signer->x509), dn->buf, sizeof(dn->buf));
+ p = strstr(dn->buf, "/CN=");
+ if (p) dn->base.cn = p+4;
+ p = strstr(dn->buf, "/O=");
+ if (p) dn->base.o = p+3;
+ p = strstr(dn->buf, "/OU=");
+ if (p) dn->base.ou = p+4;
+ p = strstr(dn->buf, "/emailAddress=");
+ if (p) dn->base.email = p+14;
+ p = strstr(dn->buf, "/C=");
+ if (p) dn->base.c = p+3;
+
+ for (p = dn->buf; *p; p++)
+ if (*p == '/')
+ *p = 0;
+
+ return (pdf_designated_name *)dn;
+}
+
+void pdf_write_digest(pdf_document *doc, char *filename, pdf_obj *byte_range, int digest_offset, int digest_length, pdf_signer *signer)
+{
+ fz_context *ctx = doc->ctx;
+ 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(byte_range)/2;
+
+ fz_var(bdata);
+ fz_var(bsegs);
+ fz_var(bp7in);
+ fz_var(bp7);
+ fz_var(p7);
+ fz_var(f);
+
+ fz_try(ctx)
+ {
+ unsigned char *p7_ptr;
+ int p7_len;
+ int i;
+
+ brange = fz_calloc(ctx, brange_len, sizeof(*brange));
+ for (i = 0; i < brange_len; i++)
+ {
+ brange[i][0] = pdf_to_int(pdf_array_get(byte_range, 2*i));
+ brange[i][1] = pdf_to_int(pdf_array_get(byte_range, 2*i+1));
+ }
+
+ bdata = BIO_new(BIO_s_file());
+ 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)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to create segment filter");
+
+ bsegs->next_bio = bdata;
+ BIO_set_segments(bsegs, brange, brange_len);
+
+ p7 = PKCS7_new();
+ if (p7 == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to create p7 object");
+
+ PKCS7_set_type(p7, NID_pkcs7_signed);
+ si = PKCS7_add_signature(p7, signer->x509, signer->pkey, EVP_sha1());
+ if (si == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to add signature");
+
+ PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data));
+ PKCS7_add_certificate(p7, signer->x509);
+
+ PKCS7_content_new(p7, NID_pkcs7_data);
+ PKCS7_set_detached(p7, 1);
+
+ bp7in = PKCS7_dataInit(p7, NULL);
+ if (bp7in == NULL)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to write to digest");
+
+ while(1)
+ {
+ char buf[4096];
+ int n = BIO_read(bsegs, buf, sizeof(buf));
+ if (n <= 0)
+ break;
+ BIO_write(bp7in, buf, n);
+ }
+
+ if (!PKCS7_dataFinal(p7, bp7in))
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to write to digest");
+
+ BIO_free(bsegs);
+ bsegs = NULL;
+ BIO_free(bdata);
+ bdata = NULL;
+
+ bp7 = BIO_new(BIO_s_mem());
+ if (bp7 == NULL || !i2d_PKCS7_bio(bp7, p7))
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to create memory buffer for digest");
+
+ p7_len = BIO_get_mem_data(bp7, &p7_ptr);
+ 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);
+
+ for (i = 0; i < p7_len; i++)
+ fprintf(f, "%02x", p7_ptr[i]);
+ }
+ fz_always(ctx)
+ {
+ PKCS7_free(p7);
+ BIO_free(bsegs);
+ BIO_free(bdata);
+ BIO_free(bp7in);
+ BIO_free(bp7);
+ if (f)
+ fclose(f);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+}
+
int pdf_check_signature(pdf_document *doc, pdf_widget *widget, char *file, char *ebuf, int ebufsize)
{
fz_context *ctx = doc->ctx;
@@ -387,6 +719,53 @@ int pdf_check_signature(pdf_document *doc, pdf_widget *widget, char *file, char
return res;
}
+void pdf_sign_signature(pdf_document *doc, pdf_widget *widget, char *sigfile, char *password)
+{
+ fz_context *ctx = doc->ctx;
+ pdf_signer *signer = pdf_read_pfx(ctx, sigfile, password);
+ pdf_designated_name *dn = NULL;
+ fz_buffer *fzbuf = NULL;
+
+ fz_try(ctx)
+ {
+ unsigned char *dn_str;
+ int first = 1;
+
+ pdf_signature_set_value(doc, ((pdf_annot *)widget)->obj, signer);
+ dn = pdf_signer_designated_name(signer);
+ fzbuf = fz_new_buffer(ctx, 256);
+ if (!dn->cn)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Certificat has no common name");
+
+ fz_buffer_printf(ctx, fzbuf, "cn=%s", dn->cn);
+
+ if (dn->o)
+ fz_buffer_printf(ctx, fzbuf, ", o=%s", dn->o);
+
+ if (dn->ou)
+ fz_buffer_printf(ctx, fzbuf, ", ou=%s", dn->ou);
+
+ if (dn->email)
+ fz_buffer_printf(ctx, fzbuf, ", email=%s", dn->email);
+
+ if (dn->c)
+ fz_buffer_printf(ctx, fzbuf, ", c=%s", dn->c);
+
+ (void)fz_buffer_storage(ctx, fzbuf, &dn_str);
+ pdf_set_signature_appearance(doc, (pdf_annot *)widget, dn->cn, dn_str, NULL);
+ }
+ fz_always(ctx)
+ {
+ pdf_drop_signer(signer);
+ pdf_free_designated_name(dn);
+ fz_drop_buffer(ctx, fzbuf);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+}
+
#else /* HAVE_OPENSSL */
int pdf_check_signature(pdf_document *doc, pdf_widget *widget, char *file, char *ebuf, int ebufsize)
@@ -395,4 +774,17 @@ int pdf_check_signature(pdf_document *doc, pdf_widget *widget, char *file, char
return 0;
}
+pdf_signer *pdf_keep_signer(pdf_signer *signer)
+{
+ return NULL;
+}
+
+void pdf_drop_signer(pdf_signer *signer)
+{
+}
+
+void pdf_write_digest(pdf_document *doc, char *filename, pdf_obj *byte_range, int digest_offset, int digest_length, pdf_signer *signer)
+{
+}
+
#endif /* HAVE_OPENSSL */
diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c
index a161c763..fd126aac 100644
--- a/source/pdf/pdf-write.c
+++ b/source/pdf/pdf-write.c
@@ -2270,6 +2270,117 @@ static void dump_object_details(pdf_document *doc, pdf_write_options *opts)
}
#endif
+static void presize_unsaved_signature_byteranges(pdf_document *doc)
+{
+ if (doc->unsaved_sigs)
+ {
+ /* The ByteRange objects of signatures are initially written out with
+ * dummy values, and then overwritten later. We need to make sure their
+ * initial form at least takes enough sufficient file space */
+ pdf_unsaved_sig *usig;
+ int n = 0;
+
+ for (usig = doc->unsaved_sigs; usig; usig = usig->next)
+ n++;
+
+ for (usig = doc->unsaved_sigs; usig; usig = usig->next)
+ {
+ /* There will be segments of bytes at the beginning, at
+ * the end and between each consecutive pair of signatures,
+ * hence n + 1 */
+ int i;
+ pdf_obj *byte_range = pdf_dict_getp(usig->field, "V/ByteRange");
+
+ for (i = 0; i < n+1; i++)
+ {
+ pdf_array_push_drop(byte_range, pdf_new_int(doc, INT_MAX));
+ pdf_array_push_drop(byte_range, pdf_new_int(doc, INT_MAX));
+ }
+ }
+ }
+}
+
+static void complete_signatures(pdf_document *doc, pdf_write_options *opts, char *filename)
+{
+ fz_context *ctx = doc->ctx;
+ pdf_unsaved_sig *usig;
+ FILE *f;
+ char buf[5120];
+ int i;
+ int flen;
+ int last_end;
+
+ if (doc->unsaved_sigs)
+ {
+ pdf_obj *byte_range;
+
+ f = fopen(filename, "rb+");
+ if (!f)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to open %s to complete signatures", filename);
+
+ fseek(f, 0, SEEK_END);
+ flen = ftell(f);
+
+ /* Locate the byte ranges and contents in the saved file */
+ for (usig = doc->unsaved_sigs; usig; usig = usig->next)
+ {
+ char *bstr, *cstr, *fstr;
+ int pnum = pdf_obj_parent_num(pdf_dict_getp(usig->field, "V/ByteRange"));
+ fseek(f, opts->ofs_list[pnum], SEEK_SET);
+ (void)fread(buf, 1, sizeof(buf), f);
+ 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(doc, 4);
+ pdf_dict_putp_drop(doc->unsaved_sigs->field, "V/ByteRange", byte_range);
+
+ last_end = 0;
+ for (usig = doc->unsaved_sigs; usig; usig = usig->next)
+ {
+ pdf_array_push_drop(byte_range, pdf_new_int(doc, last_end));
+ pdf_array_push_drop(byte_range, pdf_new_int(doc, usig->contents_start - last_end));
+ last_end = usig->contents_end;
+ }
+ pdf_array_push_drop(byte_range, pdf_new_int(doc, last_end));
+ pdf_array_push_drop(byte_range, pdf_new_int(doc, flen - last_end));
+
+ /* Copy the new ByteRange to the other unsaved signatures */
+ for (usig = doc->unsaved_sigs->next; usig; usig = usig->next)
+ pdf_dict_putp_drop(usig->field, "V/ByteRange", pdf_copy_array(byte_range));
+
+ /* Write the byte range into buf, padding with spaces*/
+ i = pdf_sprint_obj(buf, sizeof(buf), byte_range, 1);
+ memset(buf+i, ' ', sizeof(buf)-i);
+
+ /* Write the byte range to the file */
+ for (usig = doc->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);
+ }
+
+ fclose(f);
+
+ /* Write the digests into the file */
+ for (usig = doc->unsaved_sigs; usig; usig = usig->next)
+ pdf_write_digest(doc, filename, byte_range, usig->contents_start, usig->contents_end - usig->contents_start, usig->signer);
+ }
+}
+
void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_opts)
{
int lastfree;
@@ -2285,6 +2396,7 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_
ctx = doc->ctx;
pdf_finish_edit(doc);
+ presize_unsaved_signature_byteranges(doc);
xref_len = pdf_xref_len(doc);
@@ -2415,6 +2527,10 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_
writexref(doc, &opts, 0, xref_len, 1, 0, opts.first_xref_offset);
}
+ fclose(opts.out);
+ opts.out = NULL;
+ complete_signatures(doc, &opts, filename);
+
doc->dirty = 0;
}
fz_always(ctx)
@@ -2439,7 +2555,8 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_
pdf_drop_obj(opts.hints_s);
pdf_drop_obj(opts.hints_length);
page_objects_list_destroy(ctx, opts.page_object_lists);
- fclose(opts.out);
+ if (opts.out)
+ fclose(opts.out);
doc->freeze_updates = 0;
}
fz_catch(ctx)
diff --git a/source/pdf/pdf-xref.c b/source/pdf/pdf-xref.c
index 27c039cd..eaf250cf 100644
--- a/source/pdf/pdf-xref.c
+++ b/source/pdf/pdf-xref.c
@@ -1165,6 +1165,7 @@ void
pdf_close_document(pdf_document *doc)
{
fz_context *ctx;
+ pdf_unsaved_sig *usig;
int i;
if (!doc)
@@ -1201,6 +1202,14 @@ pdf_close_document(pdf_document *doc)
fz_free(ctx, doc->hint_shared);
fz_free(ctx, doc->hint_obj_offsets);
+ while ((usig = doc->unsaved_sigs) != NULL)
+ {
+ doc->unsaved_sigs = usig->next;
+ pdf_drop_obj(usig->field);
+ pdf_drop_signer(usig->signer);
+ fz_free(ctx, usig);
+ }
+
for (i=0; i < doc->num_type3_fonts; i++)
{
fz_decouple_type3_font(ctx, doc->type3_fonts[i], (void *)doc);
@@ -1780,6 +1789,8 @@ pdf_update_object(pdf_document *doc, int num, pdf_obj *newobj)
x->type = 'n';
x->ofs = 0;
x->obj = pdf_keep_obj(newobj);
+
+ pdf_set_obj_parent(newobj, num);
}
void