comparison mupdf-source/source/pdf/pdf-signature.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // Copyright (C) 2004-2025 Artifex Software, Inc.
2 //
3 // This file is part of MuPDF.
4 //
5 // MuPDF is free software: you can redistribute it and/or modify it under the
6 // terms of the GNU Affero General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or (at your option)
8 // any later version.
9 //
10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17 //
18 // Alternative licensing terms are available from the licensor.
19 // For commercial licensing, see <https://www.artifex.com/> or contact
20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21 // CA 94129, USA, for further information.
22
23 #include "mupdf/fitz.h"
24 #include "pdf-annot-imp.h"
25
26 #include <string.h>
27 #include <time.h>
28
29 enum
30 {
31 PDF_SIGFLAGS_SIGSEXIST = 1,
32 PDF_SIGFLAGS_APPENDONLY = 2
33 };
34
35 static void
36 begin_widget_op(fz_context *ctx, pdf_annot *annot, const char *op)
37 {
38 if (!annot->page)
39 fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation not bound to any page");
40
41 pdf_begin_operation(ctx, annot->page->doc, op);
42 }
43
44 static void
45 end_widget_op(fz_context *ctx, pdf_annot *annot)
46 {
47 pdf_end_operation(ctx, annot->page->doc);
48 }
49
50 static void
51 abandon_widget_op(fz_context *ctx, pdf_annot *annot)
52 {
53 pdf_abandon_operation(ctx, annot->page->doc);
54 }
55
56 void pdf_write_digest(fz_context *ctx, fz_output *out, pdf_obj *byte_range, pdf_obj *field, size_t hexdigest_offset, size_t hexdigest_length, pdf_pkcs7_signer *signer)
57 {
58 fz_stream *stm = NULL;
59 fz_stream *in = NULL;
60 fz_range *brange = NULL;
61 int brange_len = pdf_array_len(ctx, byte_range)/2;
62 unsigned char *digest = NULL;
63 size_t digest_len;
64 pdf_obj *v = pdf_dict_get(ctx, field, PDF_NAME(V));
65 size_t len;
66 char *cstr = NULL;
67
68 fz_var(stm);
69 fz_var(in);
70 fz_var(brange);
71 fz_var(digest);
72 fz_var(cstr);
73
74 if (hexdigest_length < 4)
75 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Bad parameters to pdf_write_digest");
76
77 len = (hexdigest_length - 2) / 2;
78
79 fz_try(ctx)
80 {
81 int i;
82 size_t z;
83
84 brange = fz_calloc(ctx, brange_len, sizeof(*brange));
85 for (i = 0; i < brange_len; i++)
86 {
87 brange[i].offset = pdf_array_get_int(ctx, byte_range, 2*i);
88 brange[i].length = pdf_array_get_int(ctx, byte_range, 2*i+1);
89 }
90
91 stm = fz_stream_from_output(ctx, out);
92 in = fz_open_range_filter(ctx, stm, brange, brange_len);
93
94 digest = fz_malloc(ctx, len);
95 digest_len = signer->create_digest(ctx, signer, in, digest, len);
96 if (digest_len == 0)
97 fz_throw(ctx, FZ_ERROR_ARGUMENT, "signer provided no signature digest");
98 if (digest_len > len)
99 fz_throw(ctx, FZ_ERROR_ARGUMENT, "signature digest larger than space for digest");
100
101 fz_drop_stream(ctx, in);
102 in = NULL;
103 fz_drop_stream(ctx, stm);
104 stm = NULL;
105
106 fz_seek_output(ctx, out, (int64_t)hexdigest_offset+1, SEEK_SET);
107 cstr = fz_malloc(ctx, len);
108
109 for (z = 0; z < len; z++)
110 {
111 int val = z < digest_len ? digest[z] : 0;
112 fz_write_printf(ctx, out, "%02x", val);
113 cstr[z] = val;
114 }
115
116 pdf_dict_put_string(ctx, v, PDF_NAME(Contents), cstr, len);
117 }
118 fz_always(ctx)
119 {
120 fz_free(ctx, cstr);
121 fz_free(ctx, digest);
122 fz_free(ctx, brange);
123 fz_drop_stream(ctx, stm);
124 fz_drop_stream(ctx, in);
125 }
126 fz_catch(ctx)
127 {
128 fz_rethrow(ctx);
129 }
130 }
131
132 typedef struct fieldname_prefix
133 {
134 struct fieldname_prefix *prev;
135 char name[FZ_FLEXIBLE_ARRAY];
136 } fieldname_prefix;
137
138 typedef struct
139 {
140 pdf_locked_fields *locked;
141 fieldname_prefix *prefix;
142 } sig_locking_data;
143
144 static void
145 check_field_locking(fz_context *ctx, pdf_obj *obj, void *data_, pdf_obj **ff)
146 {
147 fieldname_prefix *prefix = NULL;
148 sig_locking_data *data = (sig_locking_data *)data_;
149
150 fz_var(prefix);
151
152 fz_try(ctx)
153 {
154 const char *name = NULL;
155 size_t n = 1;
156 pdf_obj *t;
157
158 t = pdf_dict_get(ctx, obj, PDF_NAME(T));
159 if (t != NULL)
160 {
161 name = pdf_to_text_string(ctx, t);
162 n += strlen(name);
163 }
164 if (data->prefix->name[0] && name)
165 n += 1;
166 if (data->prefix->name[0])
167 n += strlen(data->prefix->name);
168 prefix = fz_malloc_flexible(ctx, fieldname_prefix, name, n);
169 prefix->prev = data->prefix;
170 if (data->prefix->name[0])
171 strcpy(prefix->name, data->prefix->name);
172 if (data->prefix->name[0] && name)
173 strcat(prefix->name, ".");
174 if (name)
175 strcat(prefix->name, name);
176 data->prefix = prefix;
177
178 if (pdf_name_eq(ctx, pdf_dict_get(ctx, obj, PDF_NAME(Type)), PDF_NAME(Annot)) &&
179 pdf_name_eq(ctx, pdf_dict_get(ctx, obj, PDF_NAME(Subtype)), PDF_NAME(Widget)))
180 {
181 int flags = pdf_to_int(ctx, *ff);
182
183 if (((flags & PDF_FIELD_IS_READ_ONLY) == 0) && /* Field is not currently locked */
184 pdf_is_field_locked(ctx, data->locked, data->prefix->name)) /* Field should be locked */
185 pdf_dict_put_int(ctx, obj, PDF_NAME(Ff), flags | PDF_FIELD_IS_READ_ONLY);
186 }
187 }
188 fz_catch(ctx)
189 {
190 if (prefix)
191 {
192 data->prefix = prefix->prev;
193 fz_free(ctx, prefix);
194 }
195 fz_rethrow(ctx);
196 }
197 }
198
199 static void
200 pop_field_locking(fz_context *ctx, pdf_obj *obj, void *data_)
201 {
202 fieldname_prefix *prefix;
203 sig_locking_data *data = (sig_locking_data *)data_;
204
205 prefix = data->prefix;
206 data->prefix = data->prefix->prev;
207 fz_free(ctx, prefix);
208 }
209
210 static void enact_sig_locking(fz_context *ctx, pdf_document *doc, pdf_obj *sig)
211 {
212 pdf_locked_fields *locked = pdf_find_locked_fields_for_sig(ctx, doc, sig);
213 pdf_obj *fields;
214 static pdf_obj *ff_names[2] = { PDF_NAME(Ff), NULL };
215 pdf_obj *ff = NULL;
216 static fieldname_prefix null_prefix = { NULL, { 0 } };
217 sig_locking_data data = { locked, &null_prefix };
218
219 if (locked == NULL)
220 return;
221
222 fz_try(ctx)
223 {
224 fields = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/AcroForm/Fields");
225 pdf_walk_tree(ctx, fields, PDF_NAME(Kids), check_field_locking, pop_field_locking, &data, &ff_names[0], &ff);
226 }
227 fz_always(ctx)
228 pdf_drop_locked_fields(ctx, locked);
229 fz_catch(ctx)
230 {
231 pop_field_locking(ctx, NULL, &data);
232 fz_rethrow(ctx);
233 }
234 }
235
236 void
237 pdf_sign_signature_with_appearance(fz_context *ctx, pdf_annot *widget, pdf_pkcs7_signer *signer, int64_t t, fz_display_list *disp_list)
238 {
239 pdf_document *doc;
240
241 if (pdf_dict_get_inheritable(ctx, widget->obj, PDF_NAME(FT)) != PDF_NAME(Sig))
242 fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation is not a signature widget");
243 if (pdf_widget_is_readonly(ctx, widget))
244 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Signature is read only, it cannot be signed.");
245
246 begin_widget_op(ctx, widget, "Sign signature");
247 doc = widget->page->doc;
248
249 fz_try(ctx)
250 {
251 pdf_obj *wobj = ((pdf_annot *)widget)->obj;
252 pdf_obj *form;
253 int sf;
254
255 pdf_dirty_annot(ctx, widget);
256
257 /* Ensure that all fields that will be locked by this signature
258 * are marked as ReadOnly. */
259 enact_sig_locking(ctx, doc, wobj);
260
261 if (disp_list)
262 pdf_set_annot_appearance_from_display_list(ctx, widget, "N", NULL, fz_identity, disp_list);
263
264 /* Update the SigFlags for the document if required */
265 form = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/AcroForm");
266 if (!form)
267 {
268 pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root));
269 form = pdf_dict_put_dict(ctx, root, PDF_NAME(AcroForm), 1);
270 }
271
272 sf = pdf_to_int(ctx, pdf_dict_get(ctx, form, PDF_NAME(SigFlags)));
273 if ((sf & (PDF_SIGFLAGS_SIGSEXIST | PDF_SIGFLAGS_APPENDONLY)) != (PDF_SIGFLAGS_SIGSEXIST | PDF_SIGFLAGS_APPENDONLY))
274 pdf_dict_put_int(ctx, form, PDF_NAME(SigFlags), sf | PDF_SIGFLAGS_SIGSEXIST | PDF_SIGFLAGS_APPENDONLY);
275
276 pdf_signature_set_value(ctx, doc, wobj, signer, t);
277 end_widget_op(ctx, widget);
278 }
279 fz_catch(ctx)
280 {
281 abandon_widget_op(ctx, widget);
282 fz_rethrow(ctx);
283 }
284 }
285
286 static pdf_pkcs7_distinguished_name placeholder_dn = {
287 "Your Common Name Here",
288 "Organization",
289 "Organizational Unit",
290 "Email",
291 "Country"
292 };
293
294 static char *
295 pdf_format_signature_info(fz_context *ctx, pdf_pkcs7_signer *signer, int flags, const char *reason, const char *location, int64_t now, char **name)
296 {
297 pdf_pkcs7_distinguished_name *dn = NULL;
298 char *info;
299 fz_var(dn);
300 fz_try(ctx)
301 {
302 if (signer)
303 dn = signer->get_signing_name(ctx, signer);
304 if (!dn)
305 dn = &placeholder_dn;
306 *name = fz_strdup(ctx, dn->cn ? dn->cn : "Your Common Name Here");
307 info = pdf_signature_info(ctx,
308 (flags & PDF_SIGNATURE_SHOW_TEXT_NAME) ? *name : NULL,
309 (flags & PDF_SIGNATURE_SHOW_DN) ? dn : NULL,
310 reason,
311 location,
312 (flags & PDF_SIGNATURE_SHOW_DATE) ? now : -1,
313 (flags & PDF_SIGNATURE_SHOW_LABELS) ? 1 : 0);
314 }
315 fz_always(ctx)
316 {
317 if (dn != &placeholder_dn)
318 pdf_signature_drop_distinguished_name(ctx, dn);
319 }
320 fz_catch(ctx)
321 fz_rethrow(ctx);
322 return info;
323 }
324
325
326 void pdf_sign_signature(fz_context *ctx, pdf_annot *widget,
327 pdf_pkcs7_signer *signer,
328 int flags,
329 fz_image *graphic,
330 const char *reason,
331 const char *location)
332 {
333 int logo = flags & PDF_SIGNATURE_SHOW_LOGO;
334 fz_rect rect = pdf_annot_rect(ctx, widget);
335 fz_text_language lang = pdf_annot_language(ctx, widget);
336 #ifdef CLUSTER
337 int64_t now = 1112281971; /* release date of MuPDF 0.1 */
338 #else
339 int64_t now = time(NULL);
340 #endif
341 char *name = NULL;
342 char *info = NULL;
343 fz_display_list *dlist = NULL;
344
345 fz_var(dlist);
346 fz_var(info);
347 fz_var(name);
348
349 /* Create an appearance stream only if the signature is intended to be visible */
350 fz_try(ctx)
351 {
352 if (!fz_is_empty_rect(rect))
353 {
354 info = pdf_format_signature_info(ctx, signer, flags, reason, location, now, &name);
355 if (graphic)
356 dlist = pdf_signature_appearance_signed(ctx, rect, lang, graphic, NULL, info, logo);
357 else if (flags & PDF_SIGNATURE_SHOW_GRAPHIC_NAME)
358 dlist = pdf_signature_appearance_signed(ctx, rect, lang, NULL, name, info, logo);
359 else
360 dlist = pdf_signature_appearance_signed(ctx, rect, lang, NULL, NULL, info, logo);
361 }
362 pdf_sign_signature_with_appearance(ctx, widget, signer, now, dlist);
363 }
364 fz_always(ctx)
365 {
366 fz_free(ctx, info);
367 fz_free(ctx, name);
368 fz_drop_display_list(ctx, dlist);
369 }
370 fz_catch(ctx)
371 fz_rethrow(ctx);
372 }
373
374 fz_display_list *pdf_preview_signature_as_display_list(fz_context *ctx,
375 float w, float h, fz_text_language lang,
376 pdf_pkcs7_signer *signer,
377 int flags,
378 fz_image *graphic,
379 const char *reason,
380 const char *location)
381 {
382 int logo = flags & PDF_SIGNATURE_SHOW_LOGO;
383 fz_rect rect = fz_make_rect(0, 0, w, h);
384 int64_t now = time(NULL);
385 char *name = NULL;
386 char *info = NULL;
387 fz_display_list *dlist = NULL;
388
389 fz_var(dlist);
390 fz_var(info);
391 fz_var(name);
392
393 fz_try(ctx)
394 {
395 info = pdf_format_signature_info(ctx, signer, flags, reason, location, now, &name);
396 if (graphic)
397 dlist = pdf_signature_appearance_signed(ctx, rect, lang, graphic, NULL, info, logo);
398 else if (flags & PDF_SIGNATURE_SHOW_GRAPHIC_NAME)
399 dlist = pdf_signature_appearance_signed(ctx, rect, lang, NULL, name, info, logo);
400 else
401 dlist = pdf_signature_appearance_signed(ctx, rect, lang, NULL, NULL, info, logo);
402 }
403 fz_always(ctx)
404 {
405 fz_free(ctx, info);
406 fz_free(ctx, name);
407 }
408 fz_catch(ctx)
409 fz_rethrow(ctx);
410
411 return dlist;
412 }
413
414 fz_pixmap *pdf_preview_signature_as_pixmap(fz_context *ctx,
415 int w, int h, fz_text_language lang,
416 pdf_pkcs7_signer *signer,
417 int flags,
418 fz_image *graphic,
419 const char *reason,
420 const char *location)
421 {
422 fz_pixmap *pix;
423 fz_display_list *dlist = pdf_preview_signature_as_display_list(ctx,
424 w, h, lang,
425 signer, flags, graphic, reason, location);
426 fz_try(ctx)
427 pix = fz_new_pixmap_from_display_list(ctx, dlist, fz_identity, fz_device_rgb(ctx), 0);
428 fz_always(ctx)
429 fz_drop_display_list(ctx, dlist);
430 fz_catch(ctx)
431 fz_rethrow(ctx);
432 return pix;
433 }
434
435 void pdf_clear_signature(fz_context *ctx, pdf_annot *widget)
436 {
437 int flags;
438 fz_display_list *dlist = NULL;
439
440 if (pdf_dict_get_inheritable(ctx, widget->obj, PDF_NAME(FT)) != PDF_NAME(Sig))
441 fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation is not a signature widget");
442 if (pdf_widget_is_readonly(ctx, widget))
443 fz_throw(ctx, FZ_ERROR_ARGUMENT, "read only signature cannot be cleared");
444
445 begin_widget_op(ctx, widget, "Clear Signature");
446
447 fz_var(dlist);
448 fz_try(ctx)
449 {
450 fz_text_language lang = pdf_annot_language(ctx, (pdf_annot *)widget);
451 fz_rect rect = pdf_annot_rect(ctx, widget);
452
453 pdf_begin_operation(ctx, widget->page->doc, "Clear Signature");
454 if (pdf_widget_is_readonly(ctx, widget))
455 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Signature read only, it cannot be cleared.");
456
457 pdf_xref_remove_unsaved_signature(ctx, ((pdf_annot *)widget)->page->doc, ((pdf_annot *)widget)->obj);
458
459 pdf_dirty_annot(ctx, widget);
460
461 flags = pdf_dict_get_int(ctx, ((pdf_annot *)widget)->obj, PDF_NAME(F));
462 flags &= ~PDF_ANNOT_IS_LOCKED;
463 if (flags)
464 pdf_dict_put_int(ctx, ((pdf_annot *)widget)->obj, PDF_NAME(F), flags);
465 else
466 pdf_dict_del(ctx, ((pdf_annot *)widget)->obj, PDF_NAME(F));
467
468 pdf_dict_del(ctx, ((pdf_annot *)widget)->obj, PDF_NAME(V));
469
470 dlist = pdf_signature_appearance_unsigned(ctx, rect, lang);
471 pdf_set_annot_appearance_from_display_list(ctx, widget, "N", NULL, fz_identity, dlist);
472 end_widget_op(ctx, widget);
473 }
474 fz_always(ctx)
475 {
476 fz_drop_display_list(ctx, dlist);
477 }
478 fz_catch(ctx)
479 {
480 abandon_widget_op(ctx, widget);
481 fz_rethrow(ctx);
482 }
483 }
484
485 void pdf_drop_signer(fz_context *ctx, pdf_pkcs7_signer *signer)
486 {
487 if (signer)
488 signer->drop(ctx, signer);
489 }
490
491 void pdf_drop_verifier(fz_context *ctx, pdf_pkcs7_verifier *verifier)
492 {
493 if (verifier)
494 verifier->drop(ctx, verifier);
495 }
496
497 char *pdf_signature_error_description(pdf_signature_error err)
498 {
499 switch (err)
500 {
501 case PDF_SIGNATURE_ERROR_OKAY:
502 return "OK";
503 case PDF_SIGNATURE_ERROR_NO_SIGNATURES:
504 return "No signatures.";
505 case PDF_SIGNATURE_ERROR_NO_CERTIFICATE:
506 return "No certificate.";
507 case PDF_SIGNATURE_ERROR_DIGEST_FAILURE:
508 return "Signature invalidated by change to document.";
509 case PDF_SIGNATURE_ERROR_SELF_SIGNED:
510 return "Self-signed certificate.";
511 case PDF_SIGNATURE_ERROR_SELF_SIGNED_IN_CHAIN:
512 return "Self-signed certificate in chain.";
513 case PDF_SIGNATURE_ERROR_NOT_TRUSTED:
514 return "Certificate not trusted.";
515 default:
516 case PDF_SIGNATURE_ERROR_UNKNOWN:
517 return "Unknown error.";
518 }
519 }
520
521 void pdf_signature_drop_distinguished_name(fz_context *ctx, pdf_pkcs7_distinguished_name *dn)
522 {
523 if (dn)
524 {
525 fz_free(ctx, dn->c);
526 fz_free(ctx, dn->email);
527 fz_free(ctx, dn->ou);
528 fz_free(ctx, dn->o);
529 fz_free(ctx, dn->cn);
530 fz_free(ctx, dn);
531 }
532 }
533
534 char *pdf_signature_format_distinguished_name(fz_context *ctx, pdf_pkcs7_distinguished_name *name)
535 {
536 const char *parts[] = {
537 "cn=", "",
538 ", o=", "",
539 ", ou=", "",
540 ", email=", "",
541 ", c=", ""};
542 size_t len = 1;
543 char *s;
544 int i;
545
546 if (name == NULL)
547 return NULL;
548
549 parts[1] = name->cn;
550 parts[3] = name->o;
551 parts[5] = name->ou;
552 parts[7] = name->email;
553 parts[9] = name->c;
554
555 for (i = 0; i < (int)nelem(parts); i++)
556 if (parts[i])
557 len += strlen(parts[i]);
558
559 s = fz_malloc(ctx, len);
560 s[0] = '\0';
561
562 for (i = 0; i < (int)nelem(parts); i++)
563 if (parts[i])
564 fz_strlcat(s, parts[i], len);
565
566 return s;
567 }
568
569 pdf_pkcs7_distinguished_name *pdf_signature_get_widget_signatory(fz_context *ctx, pdf_pkcs7_verifier *verifier, pdf_annot *widget)
570 {
571 if (!widget->page)
572 fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation not bound to any page");
573 return pdf_signature_get_signatory(ctx, verifier, widget->page->doc, widget->obj);
574 }
575
576 pdf_pkcs7_distinguished_name *pdf_signature_get_signatory(fz_context *ctx, pdf_pkcs7_verifier *verifier, pdf_document *doc, pdf_obj *signature)
577 {
578 char *contents = NULL;
579 size_t contents_len;
580 pdf_pkcs7_distinguished_name *dn;
581
582 if (pdf_dict_get_inheritable(ctx, signature, PDF_NAME(FT)) != PDF_NAME(Sig))
583 fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation is not a signature widget");
584 if (!pdf_signature_is_signed(ctx, doc, signature))
585 return NULL;
586
587 contents_len = pdf_signature_contents(ctx, doc, signature, &contents);
588 if (contents_len == 0)
589 return NULL;
590
591 fz_try(ctx)
592 dn = verifier->get_signatory(ctx, verifier, (unsigned char *)contents, contents_len);
593 fz_always(ctx)
594 fz_free(ctx, contents);
595 fz_catch(ctx)
596 fz_rethrow(ctx);
597
598 return dn;
599 }
600
601 pdf_signature_error pdf_check_widget_digest(fz_context *ctx, pdf_pkcs7_verifier *verifier, pdf_annot *widget)
602 {
603 if (!widget->page)
604 fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation not bound to any page");
605 return pdf_check_digest(ctx, verifier, widget->page->doc, widget->obj);
606 }
607
608 pdf_signature_error pdf_check_digest(fz_context *ctx, pdf_pkcs7_verifier *verifier, pdf_document *doc, pdf_obj *signature)
609 {
610 pdf_signature_error result = PDF_SIGNATURE_ERROR_UNKNOWN;
611 fz_stream *bytes = NULL;
612 char *contents = NULL;
613 size_t contents_len;
614
615 if (pdf_dict_get_inheritable(ctx, signature, PDF_NAME(FT)) != PDF_NAME(Sig))
616 fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation is not a signature widget");
617 if (!pdf_signature_is_signed(ctx, doc, signature))
618 return PDF_SIGNATURE_ERROR_NOT_SIGNED;
619
620 contents_len = pdf_signature_contents(ctx, doc, signature, &contents);
621
622 fz_var(bytes);
623 fz_try(ctx)
624 {
625 bytes = pdf_signature_hash_bytes(ctx, doc, signature);
626 result = verifier->check_digest(ctx, verifier, bytes, (unsigned char *)contents, contents_len);
627 }
628 fz_always(ctx)
629 {
630 fz_drop_stream(ctx, bytes);
631 fz_free(ctx, contents);
632 }
633 fz_catch(ctx)
634 {
635 fz_rethrow(ctx);
636 }
637
638 return result;
639 }
640
641 pdf_signature_error pdf_check_widget_certificate(fz_context *ctx, pdf_pkcs7_verifier *verifier, pdf_annot *w)
642 {
643 if (!w->page)
644 fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation not bound to any page");
645 return pdf_check_certificate(ctx, verifier, w->page->doc, w->obj);
646 }
647
648 pdf_signature_error pdf_check_certificate(fz_context *ctx, pdf_pkcs7_verifier *verifier, pdf_document *doc, pdf_obj *signature)
649 {
650 char *contents = NULL;
651 size_t contents_len;
652 pdf_signature_error result = PDF_SIGNATURE_ERROR_UNKNOWN;
653
654 if (pdf_dict_get_inheritable(ctx, signature, PDF_NAME(FT)) != PDF_NAME(Sig))
655 fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation is not a signature widget");
656 if (!pdf_signature_is_signed(ctx, doc, signature))
657 return PDF_SIGNATURE_ERROR_NOT_SIGNED;
658
659 contents_len = pdf_signature_contents(ctx, doc, signature, &contents);
660
661 fz_try(ctx)
662 result = verifier->check_certificate(ctx, verifier, (unsigned char *)contents, contents_len);
663 fz_always(ctx)
664 fz_free(ctx, contents);
665 fz_catch(ctx)
666 fz_rethrow(ctx);
667 return result;
668 }