Coverage Report

Created: 2023-06-07 06:20

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