summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mupdf/pdf.h2
-rw-r--r--include/mupdf/pdf/crypt.h30
-rw-r--r--include/mupdf/pdf/document.h4
-rw-r--r--include/mupdf/pdf/field.h2
-rw-r--r--include/mupdf/pdf/pdf-pkcs7.h56
-rw-r--r--include/mupdf/pdf/xref.h2
-rw-r--r--platform/win32/libmupdf.vcproj8
-rw-r--r--source/pdf/pdf-form.c2
-rw-r--r--source/pdf/pdf-pkcs7.c389
-rw-r--r--source/pdf/pdf-signature.c243
-rw-r--r--source/pdf/pdf-write.c2
-rw-r--r--source/pdf/pdf-xref.c6
12 files changed, 419 insertions, 327 deletions
diff --git a/include/mupdf/pdf.h b/include/mupdf/pdf.h
index eab70ee9..f593e680 100644
--- a/include/mupdf/pdf.h
+++ b/include/mupdf/pdf.h
@@ -31,6 +31,8 @@ extern "C" {
#include "mupdf/pdf/clean.h"
+#include "mupdf/pdf/pdf-pkcs7.h"
+
#ifdef __cplusplus
}
#endif
diff --git a/include/mupdf/pdf/crypt.h b/include/mupdf/pdf/crypt.h
index 555a8d25..59513acc 100644
--- a/include/mupdf/pdf/crypt.h
+++ b/include/mupdf/pdf/crypt.h
@@ -21,35 +21,7 @@ unsigned char *pdf_crypt_key(fz_context *ctx, pdf_document *doc);
void pdf_print_crypt(fz_context *ctx, fz_output *out, pdf_crypt *crypt);
-typedef enum
-{
- SignatureError_Okay,
- SignatureError_NoSignatures,
- SignatureError_NoCertificate,
- SignatureError_DocumentChanged,
- SignatureError_SelfSigned,
- SignatureError_SelfSignedInChain,
- SignatureError_NotTrusted,
- SignatureError_Unknown
-} SignatureError;
-
-typedef struct pdf_designated_name_s
-{
- char *cn;
- char *o;
- char *ou;
- char *email;
- char *c;
-}
-pdf_designated_name;
-
-void pdf_drop_designated_name(fz_context *ctx, pdf_designated_name *dn);
-
-pdf_signer *pdf_read_pfx(fz_context *ctx, const char *sigfile, const char *password);
-pdf_signer *pdf_keep_signer(fz_context *ctx, pdf_signer *signer);
-void pdf_drop_signer(fz_context *ctx, pdf_signer *signer);
-pdf_designated_name *pdf_signer_designated_name(fz_context *ctx, 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);
+void pdf_write_digest(fz_context *ctx, fz_output *out, pdf_obj *byte_range, int digest_offset, int digest_length, pdf_pkcs7_signer *signer);
/*
pdf_signature_widget_byte_range: retrieve the byte range for a signature widget
diff --git a/include/mupdf/pdf/document.h b/include/mupdf/pdf/document.h
index ebd04401..ef861145 100644
--- a/include/mupdf/pdf/document.h
+++ b/include/mupdf/pdf/document.h
@@ -535,7 +535,7 @@ void pdf_update_page(fz_context *ctx, pdf_page *page);
*/
int pdf_has_unsaved_changes(fz_context *ctx, pdf_document *doc);
-typedef struct pdf_signer_s pdf_signer;
+typedef struct pdf_pkcs7_signer_s pdf_pkcs7_signer;
/* Unsaved signature fields */
typedef struct pdf_unsaved_sig_s pdf_unsaved_sig;
@@ -547,7 +547,7 @@ struct pdf_unsaved_sig_s
int byte_range_end;
int contents_start;
int contents_end;
- pdf_signer *signer;
+ pdf_pkcs7_signer *signer;
pdf_unsaved_sig *next;
};
diff --git a/include/mupdf/pdf/field.h b/include/mupdf/pdf/field.h
index baf650f4..c3509938 100644
--- a/include/mupdf/pdf/field.h
+++ b/include/mupdf/pdf/field.h
@@ -45,7 +45,7 @@ void pdf_field_set_border_style(fz_context *ctx, pdf_document *doc, pdf_obj *fie
void pdf_field_set_button_caption(fz_context *ctx, pdf_document *doc, pdf_obj *field, const char *text);
void pdf_field_set_fill_color(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_obj *col);
void pdf_field_set_text_color(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_obj *col);
-void pdf_signature_set_value(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_signer *signer);
+void pdf_signature_set_value(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_pkcs7_signer *signer);
int pdf_field_display(fz_context *ctx, pdf_document *doc, pdf_obj *field);
char *pdf_field_name(fz_context *ctx, pdf_document *doc, pdf_obj *field);
void pdf_field_set_display(fz_context *ctx, pdf_document *doc, pdf_obj *field, int d);
diff --git a/include/mupdf/pdf/pdf-pkcs7.h b/include/mupdf/pdf/pdf-pkcs7.h
new file mode 100644
index 00000000..8f11a6b4
--- /dev/null
+++ b/include/mupdf/pdf/pdf-pkcs7.h
@@ -0,0 +1,56 @@
+#ifndef MUPDF_PDF_PKCS7_H
+#define MUPDF_PDF_PKCS7_H
+
+typedef enum
+{
+ SignatureError_Okay,
+ SignatureError_NoSignatures,
+ SignatureError_NoCertificate,
+ SignatureError_DocumentChanged,
+ SignatureError_SelfSigned,
+ SignatureError_SelfSignedInChain,
+ SignatureError_NotTrusted,
+ SignatureError_Unknown
+} SignatureError;
+
+typedef struct pdf_pkcs7_designated_name_s
+{
+ char *cn;
+ char *o;
+ char *ou;
+ char *email;
+ char *c;
+}
+pdf_pkcs7_designated_name;
+
+/* Check a signature's digest against ranges of bytes drawn from a stream */
+SignatureError pdf_pkcs7_check_digest(fz_context *ctx, fz_stream *stm, char *sig, int sig_len, int (*byte_range)[2], int byte_range_len);
+
+/* Check a singature's certificate is trusted */
+SignatureError pdf_pkcs7_check_certificate(char *sig, int sig_len);
+
+/* Obtain the designated name information from signature's certificate */
+pdf_pkcs7_designated_name *pdf_cert_designated_name(fz_context *ctx, char *sig, int sig_len);
+
+/* Free the resources associated with designated name information */
+void pdf_pkcs7_drop_designated_name(fz_context *ctx, pdf_pkcs7_designated_name *dn);
+
+/* Read the certificate and private key from a pfx file, holding it as an opaque structure */
+pdf_pkcs7_signer *pdf_pkcs7_read_pfx(fz_context *ctx, const char *pfile, const char *pw);
+
+/* Increment the reference count for a signer object */
+pdf_pkcs7_signer *pdf_pkcs7_keep_signer(fz_context *ctx, pdf_pkcs7_signer *signer);
+
+/* Drop a reference for a signer object */
+void pdf_pkcs7_drop_signer(fz_context *ctx, pdf_pkcs7_signer *signer);
+
+/* Obtain the designated name information from a signer object */
+pdf_pkcs7_designated_name *pdf_pkcs7_signer_designated_name(fz_context *ctx, pdf_pkcs7_signer *signer);
+
+/* Create a signature based on ranges of bytes drawn from a steam */
+int pdf_pkcs7_create_digest(fz_context *ctx, fz_stream *in, int brange[][2], int brange_len, pdf_pkcs7_signer *signer, unsigned char *digest, int *digest_len);
+
+/* Report whether pkcs7 is supported in the current build */
+int pdf_pkcs7_supported(fz_context *ctx);
+
+#endif
diff --git a/include/mupdf/pdf/xref.h b/include/mupdf/pdf/xref.h
index de23147e..87a84efe 100644
--- a/include/mupdf/pdf/xref.h
+++ b/include/mupdf/pdf/xref.h
@@ -105,7 +105,7 @@ pdf_xref_entry *pdf_get_xref_entry(fz_context *ctx, pdf_document *doc, int i);
void pdf_replace_xref(fz_context *ctx, pdf_document *doc, pdf_xref_entry *entries, int n);
void pdf_xref_ensure_incremental_object(fz_context *ctx, pdf_document *doc, int num);
int pdf_xref_is_incremental(fz_context *ctx, pdf_document *doc, int num);
-void pdf_xref_store_unsaved_signature(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_signer *signer);
+void pdf_xref_store_unsaved_signature(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_pkcs7_signer *signer);
int pdf_xref_obj_is_unsaved_signature(pdf_document *doc, pdf_obj *obj);
void pdf_repair_xref(fz_context *ctx, pdf_document *doc);
diff --git a/platform/win32/libmupdf.vcproj b/platform/win32/libmupdf.vcproj
index 573b0561..17217a68 100644
--- a/platform/win32/libmupdf.vcproj
+++ b/platform/win32/libmupdf.vcproj
@@ -2161,6 +2161,10 @@
>
</File>
<File
+ RelativePath="..\..\source\pdf\pdf-signature.c"
+ >
+ </File>
+ <File
RelativePath="..\..\source\pdf\pdf-store.c"
>
</File>
@@ -2284,6 +2288,10 @@
>
</File>
<File
+ RelativePath="..\..\include\mupdf\pdf\pdf-pkcs7.h"
+ >
+ </File>
+ <File
RelativePath="..\..\include\mupdf\pdf\resource.h"
>
</File>
diff --git a/source/pdf/pdf-form.c b/source/pdf/pdf-form.c
index 2ce950be..63562ef6 100644
--- a/source/pdf/pdf-form.c
+++ b/source/pdf/pdf-form.c
@@ -1304,7 +1304,7 @@ int pdf_signature_widget_contents(fz_context *ctx, pdf_document *doc, pdf_widget
return pdf_to_str_len(ctx, c);
}
-void pdf_signature_set_value(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_signer *signer)
+void pdf_signature_set_value(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_pkcs7_signer *signer)
{
pdf_obj *v = NULL;
pdf_obj *indv;
diff --git a/source/pdf/pdf-pkcs7.c b/source/pdf/pdf-pkcs7.c
index cd250ece..f095e586 100644
--- a/source/pdf/pdf-pkcs7.c
+++ b/source/pdf/pdf-pkcs7.c
@@ -498,7 +498,7 @@ exit:
return res;
}
-SignatureError pdf_signature_check_digest(fz_context *ctx, fz_stream *stm, char *sig, int sig_len, int (*byte_range)[2], int byte_range_len)
+SignatureError pdf_pkcs7_check_digest(fz_context *ctx, fz_stream *stm, char *sig, int sig_len, int (*byte_range)[2], int byte_range_len)
{
PKCS7 *pk7sig = NULL;
BIO *bsig = NULL;
@@ -534,7 +534,7 @@ exit:
return res;
}
-SignatureError pdf_signature_check_certificate(char *sig, int sig_len)
+SignatureError pdf_pkcs7_check_certificate(char *sig, int sig_len)
{
PKCS7 *pk7sig = NULL;
PKCS7 *pk7cert = NULL;
@@ -585,20 +585,20 @@ exit:
return res;
}
-typedef struct pdf_designated_name_openssl_s
+typedef struct pdf_pkcs7_designated_name_openssl_s
{
- pdf_designated_name base;
+ pdf_pkcs7_designated_name base;
char buf[8192];
-} pdf_designated_name_openssl;
+} pdf_pkcs7_designated_name_openssl;
-struct pdf_signer_s
+struct pdf_pkcs7_signer_s
{
int refs;
X509 *x509;
EVP_PKEY *pkey;
};
-void pdf_drop_designated_name(fz_context *ctx, pdf_designated_name *dn)
+void pdf_pkcs7_drop_designated_name(fz_context *ctx, pdf_pkcs7_designated_name *dn)
{
fz_free(ctx, dn);
}
@@ -664,12 +664,12 @@ static void add_from_bags(X509 **pX509, EVP_PKEY **pPkey, const STACK_OF(PKCS12_
add_from_bag(pX509, pPkey, sk_PKCS12_SAFEBAG_value(bags, i), pw);
}
-pdf_signer *pdf_read_pfx(fz_context *ctx, const char *pfile, const char *pw)
+pdf_pkcs7_signer *pdf_pkcs7_read_pfx(fz_context *ctx, const char *pfile, const char *pw)
{
BIO *pfxbio = NULL;
PKCS12 *p12 = NULL;
STACK_OF(PKCS7) *asafes;
- pdf_signer *signer = NULL;
+ pdf_pkcs7_signer *signer = NULL;
int i;
fz_var(pfxbio);
@@ -677,7 +677,7 @@ pdf_signer *pdf_read_pfx(fz_context *ctx, const char *pfile, const char *pw)
fz_var(signer);
fz_try(ctx)
{
- signer = fz_malloc_struct(ctx, pdf_signer);
+ signer = fz_malloc_struct(ctx, pdf_pkcs7_signer);
signer->refs = 1;
OpenSSL_add_all_algorithms();
@@ -743,19 +743,19 @@ pdf_signer *pdf_read_pfx(fz_context *ctx, const char *pfile, const char *pw)
}
fz_catch(ctx)
{
- pdf_drop_signer(ctx, signer);
+ pdf_pkcs7_drop_signer(ctx, signer);
fz_rethrow(ctx);
}
return signer;
}
-pdf_signer *pdf_keep_signer(fz_context *ctx, pdf_signer *signer)
+pdf_pkcs7_signer *pdf_pkcs7_keep_signer(fz_context *ctx, pdf_pkcs7_signer *signer)
{
return fz_keep_imp(ctx, signer, &signer->refs);
}
-void pdf_drop_signer(fz_context *ctx, pdf_signer *signer)
+void pdf_pkcs7_drop_signer(fz_context *ctx, pdf_pkcs7_signer *signer)
{
if (fz_drop_imp(ctx, signer, &signer->refs))
{
@@ -765,28 +765,9 @@ void pdf_drop_signer(fz_context *ctx, pdf_signer *signer)
}
}
-void pdf_print_designated_name(pdf_designated_name *name, char *buf, int buflen)
+static pdf_pkcs7_designated_name *x509_designated_name(fz_context *ctx, X509 *x509)
{
- int i, n;
- const char *part[] = {
- "/CN=", name->cn,
- "/O=", name->o,
- "/OU=", name->ou,
- "/emailAddress=", name->email,
- "/C=", name->c};
-
- if (buflen)
- buf[0] = 0;
-
- n = sizeof(part)/sizeof(*part);
- for (i = 0; i < n; i++)
- if (part[i])
- fz_strlcat(buf, part[i], buflen);
-}
-
-static pdf_designated_name *x509_designated_name(fz_context *ctx, X509 *x509)
-{
- pdf_designated_name_openssl *dn = fz_malloc_struct(ctx, pdf_designated_name_openssl);
+ pdf_pkcs7_designated_name_openssl *dn = fz_malloc_struct(ctx, pdf_pkcs7_designated_name_openssl);
char *p;
X509_NAME_oneline(X509_get_subject_name(x509), dn->buf, sizeof(dn->buf));
@@ -805,17 +786,17 @@ static pdf_designated_name *x509_designated_name(fz_context *ctx, X509 *x509)
if (*p == '/')
*p = 0;
- return (pdf_designated_name *)dn;
+ return (pdf_pkcs7_designated_name *)dn;
}
-pdf_designated_name *pdf_signer_designated_name(fz_context *ctx, pdf_signer *signer)
+pdf_pkcs7_designated_name *pdf_pkcs7_signer_designated_name(fz_context *ctx, pdf_pkcs7_signer *signer)
{
return x509_designated_name(ctx, signer->x509);
}
-void pdf_write_digest(fz_context *ctx, fz_output *out, pdf_obj *byte_range, int digest_offset, int digest_length, pdf_signer *signer)
+int pdf_pkcs7_create_digest(fz_context *ctx, fz_stream *in, int brange[][2], int brange_len, pdf_pkcs7_signer *signer, unsigned char *digest, int *digest_len)
{
- fz_stream *in = NULL;
+ int res = 0;
BIO *bdata = NULL;
BIO *bsegs = NULL;
BIO *bp7in = NULL;
@@ -823,111 +804,80 @@ void pdf_write_digest(fz_context *ctx, fz_output *out, pdf_obj *byte_range, int
PKCS7 *p7 = NULL;
PKCS7_SIGNER_INFO *si;
- 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_try(ctx)
- {
- unsigned char *p7_ptr;
- 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++)
- {
- brange[i][0] = pdf_to_int(ctx, pdf_array_get(ctx, byte_range, 2*i));
- brange[i][1] = pdf_to_int(ctx, pdf_array_get(ctx, byte_range, 2*i+1));
- }
+ unsigned char *p7_ptr;
+ int p7_len;
- bdata = BIO_new_stream(ctx, in);
- if (bdata == NULL)
- fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to create file BIO");
+ bdata = BIO_new_stream(ctx, in);
+ if (bdata == NULL)
+ goto exit;
- bsegs = BIO_new(BIO_f_segments());
- if (bsegs == NULL)
- fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to create segment filter");
+ bsegs = BIO_new(BIO_f_segments());
+ if (bsegs == NULL)
+ goto exit;
- BIO_set_next(bsegs, bdata);
- BIO_set_segments(bsegs, brange, brange_len);
+ BIO_set_next(bsegs, 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");
+ p7 = PKCS7_new();
+ if (p7 == NULL)
+ goto exit;
- 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_set_type(p7, NID_pkcs7_signed);
+ si = PKCS7_add_signature(p7, signer->x509, signer->pkey, EVP_sha1());
+ if (si == NULL)
+ goto exit;
- PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data));
- PKCS7_add_certificate(p7, signer->x509);
+ 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);
+ 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");
+ bp7in = PKCS7_dataInit(p7, NULL);
+ if (bp7in == NULL)
+ goto exit;
- while(1)
- {
- char buf[4096];
- int n = BIO_read(bsegs, buf, sizeof(buf));
- if (n <= 0)
- break;
- BIO_write(bp7in, buf, n);
- }
+ 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");
+ if (!PKCS7_dataFinal(p7, bp7in))
+ goto exit;
- BIO_free(bsegs);
- bsegs = NULL;
- BIO_free(bdata);
- bdata = NULL;
- fz_drop_stream(ctx, in);
- in = NULL;
+ 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");
+ bp7 = BIO_new(BIO_s_mem());
+ if (bp7 == NULL || !i2d_PKCS7_bio(bp7, p7))
+ goto exit;
- 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");
+ p7_len = BIO_get_mem_data(bp7, &p7_ptr);
+ if (p7_len > *digest_len)
+ goto exit;
- fz_seek_output(ctx, out, digest_offset+1, SEEK_SET);
+ memcpy(digest, p7_ptr, p7_len);
+ *digest_len = p7_len;
+ res = 1;
- for (i = 0; i < p7_len; 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);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
+exit:
+ PKCS7_free(p7);
+ BIO_free(bsegs);
+ BIO_free(bdata);
+ BIO_free(bp7in);
+ BIO_free(bp7);
+ return res;
}
-static pdf_designated_name *pdf_cert_designated_name(fz_context *ctx, char *sig, int sig_len)
+pdf_pkcs7_designated_name *pdf_cert_designated_name(fz_context *ctx, char *sig, int sig_len)
{
- pdf_designated_name *name = NULL;
+ pdf_pkcs7_designated_name *name = NULL;
PKCS7 *pk7sig = NULL;
BIO *bsig = NULL;
STACK_OF(PKCS7_SIGNER_INFO) *sk = NULL;
@@ -953,197 +903,58 @@ exit:
return name;
}
-int pdf_check_signature(fz_context *ctx, pdf_document *doc, pdf_widget *widget, char *ebuf, int ebufsize)
-{
- int (*byte_range)[2] = NULL;
- int byte_range_len;
- char *contents = NULL;
- int contents_len;
- int res = 0;
- if (pdf_xref_obj_is_unsaved_signature(doc, ((pdf_annot *)widget)->obj))
- {
- fz_strlcpy(ebuf, "Signed but document yet to be saved", ebufsize);
- if (ebufsize > 0)
- ebuf[ebufsize-1] = 0;
- return 0;
- }
-
- fz_var(byte_range);
- fz_var(res);
- fz_try(ctx)
- {
- byte_range_len = pdf_signature_widget_byte_range(ctx, doc, widget, NULL);
- if (byte_range_len)
- {
- byte_range = fz_calloc(ctx, byte_range_len, sizeof(*byte_range));
- pdf_signature_widget_byte_range(ctx, doc, widget, byte_range);
- }
-
- contents_len = pdf_signature_widget_contents(ctx, doc, widget, &contents);
- if (byte_range && contents)
- {
- SignatureError err = pdf_signature_check_digest(ctx, doc->file, contents, contents_len, byte_range, byte_range_len);
- if (err == SignatureError_Okay)
- err = pdf_signature_check_certificate(contents, contents_len);
- switch (err)
- {
- case SignatureError_Okay:
- ebuf[0] = 0;
- res = 1;
- break;
- case SignatureError_NoSignatures:
- fz_strlcpy(ebuf, "No signatures", ebufsize);
- break;
- case SignatureError_NoCertificate:
- fz_strlcpy(ebuf, "No certificate", ebufsize);
- break;
- case SignatureError_DocumentChanged:
- fz_strlcpy(ebuf, "Document changed since signing", ebufsize);
- break;
- case SignatureError_SelfSigned:
- fz_strlcpy(ebuf, "Self-signed certificate", ebufsize);
- break;
- case SignatureError_SelfSignedInChain:
- fz_strlcpy(ebuf, "Self-signed certificate in chain", ebufsize);
- break;
- case SignatureError_NotTrusted:
- fz_strlcpy(ebuf, "Certificate not trusted", ebufsize);
- break;
- default:
- case SignatureError_Unknown:
- fz_strlcpy(ebuf, "Unknown error", ebufsize);
- break;
- }
-
- switch (err)
- {
- case SignatureError_SelfSigned:
- case SignatureError_SelfSignedInChain:
- case SignatureError_NotTrusted:
- {
- pdf_designated_name *name = pdf_cert_designated_name(ctx, contents, contents_len);
- if (name)
- {
- int len;
-
- fz_strlcat(ebuf, ": ", ebufsize);
- len = strlen(ebuf);
- pdf_print_designated_name(name, ebuf + len, ebufsize - len);
- pdf_drop_designated_name(ctx, name);
- }
- }
- break;
- default:
- break;
- }
- }
- else
- {
- res = 0;
- fz_strlcpy(ebuf, "Not signed", ebufsize);
- }
- }
- fz_always(ctx)
- {
- fz_free(ctx, byte_range);
- }
- fz_catch(ctx)
- {
- res = 0;
- fz_strlcpy(ebuf, fz_caught_message(ctx), ebufsize);
- }
+int pdf_pkcs7_supported(fz_context *ctx)
+{
+ return 1;
+}
- if (ebufsize > 0)
- ebuf[ebufsize-1] = 0;
+#else /* HAVE_LIBCRYPTO */
- return res;
+SignatureError pdf_pkcs7_check_digest(fz_context *ctx, fz_stream *stm, char *sig, int sig_len, int (*byte_range)[2], int byte_range_len)
+{
+ return SignatureError_Unknown;
}
-void pdf_sign_signature(fz_context *ctx, pdf_document *doc, pdf_widget *widget, const char *sigfile, const char *password)
+SignatureError pdf_pkcs7_check_certificate(char *sig, int sig_len)
{
- pdf_signer *signer = pdf_read_pfx(ctx, sigfile, password);
- pdf_designated_name *dn = NULL;
- fz_buffer *fzbuf = NULL;
-
- fz_try(ctx)
- {
- const char *dn_str;
- pdf_obj *wobj = ((pdf_annot *)widget)->obj;
- fz_rect rect = fz_empty_rect;
-
- pdf_signature_set_value(ctx, doc, wobj, signer);
-
- pdf_to_rect(ctx, pdf_dict_get(ctx, wobj, PDF_NAME_Rect), &rect);
- /* Create an appearance stream only if the signature is intended to be visible */
- if (!fz_is_empty_rect(&rect))
- {
- dn = pdf_signer_designated_name(ctx, signer);
- fzbuf = fz_new_buffer(ctx, 256);
- if (!dn->cn)
- fz_throw(ctx, FZ_ERROR_GENERIC, "Certificate has no common name");
-
- fz_append_printf(ctx, fzbuf, "cn=%s", dn->cn);
-
- if (dn->o)
- fz_append_printf(ctx, fzbuf, ", o=%s", dn->o);
-
- if (dn->ou)
- fz_append_printf(ctx, fzbuf, ", ou=%s", dn->ou);
-
- if (dn->email)
- fz_append_printf(ctx, fzbuf, ", email=%s", dn->email);
-
- if (dn->c)
- fz_append_printf(ctx, fzbuf, ", c=%s", dn->c);
-
- dn_str = fz_string_from_buffer(ctx, fzbuf);
- pdf_set_signature_appearance(ctx, doc, (pdf_annot *)widget, dn->cn, dn_str, NULL);
- }
- }
- fz_always(ctx)
- {
- pdf_drop_signer(ctx, signer);
- pdf_drop_designated_name(ctx, dn);
- fz_drop_buffer(ctx, fzbuf);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
+ return SignatureError_Unknown;
}
-int pdf_signatures_supported(fz_context *ctx)
+pdf_pkcs7_designated_name *pdf_cert_designated_name(fz_context *ctx, char *sig, int sig_len)
{
- return 1;
+ return NULL;
}
-#else /* HAVE_LIBCRYPTO */
-
-int pdf_check_signature(fz_context *ctx, pdf_document *doc, pdf_widget *widget, char *ebuf, int ebufsize)
+void pdf_pkcs7_drop_designated_name(fz_context *ctx, pdf_pkcs7_designated_name *dn)
{
- fz_strlcpy(ebuf, "This version of MuPDF was built without signature support", ebufsize);
- return 0;
}
-void pdf_sign_signature(fz_context *ctx, pdf_document *doc, pdf_widget *widget, const char *sigfile, const char *password)
+pdf_pkcs7_signer *pdf_pkcs7_read_pfx(fz_context *ctx, const char *pfile, const char *pw)
{
+ return NULL;
}
-pdf_signer *pdf_keep_signer(fz_context *ctx, pdf_signer *signer)
+pdf_pkcs7_signer *pdf_pkcs7_keep_signer(fz_context *ctx, pdf_pkcs7_signer *signer)
{
return NULL;
}
-void pdf_drop_signer(fz_context *ctx, pdf_signer *signer)
+void pdf_pkcs7_drop_signer(fz_context *ctx, pdf_pkcs7_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)
+pdf_pkcs7_designated_name *pdf_pkcs7_signer_designated_name(fz_context *ctx, pdf_pkcs7_signer *signer)
{
+ return NULL;
+}
+
+int pdf_pkcs7_create_digest(fz_context *ctx, fz_stream *in, int brange[][2], int brange_len, pdf_pkcs7_signer *signer, unsigned char *digest, int *digest_len)
+{
+ return 0;
}
-int pdf_signatures_supported(fz_context *ctx)
+int pdf_pkcs7_supported(fz_context *ctx)
{
return 0;
}
diff --git a/source/pdf/pdf-signature.c b/source/pdf/pdf-signature.c
new file mode 100644
index 00000000..ade5bc57
--- /dev/null
+++ b/source/pdf/pdf-signature.c
@@ -0,0 +1,243 @@
+#include "mupdf/fitz.h"
+#include "mupdf/pdf.h"
+#include "../fitz/fitz-imp.h"
+
+#include <string.h>
+
+
+static void pdf_print_designated_name(pdf_pkcs7_designated_name *name, char *buf, int buflen)
+{
+ int i, n;
+ const char *part[] = {
+ "/CN=", name->cn,
+ "/O=", name->o,
+ "/OU=", name->ou,
+ "/emailAddress=", name->email,
+ "/C=", name->c};
+
+ if (buflen)
+ buf[0] = 0;
+
+ n = sizeof(part)/sizeof(*part);
+ for (i = 0; i < n; i++)
+ if (part[i])
+ fz_strlcat(buf, part[i], buflen);
+}
+
+void pdf_write_digest(fz_context *ctx, fz_output *out, pdf_obj *byte_range, int hexdigest_offset, int hexdigest_length, pdf_pkcs7_signer *signer)
+{
+ fz_stream *in = NULL;
+ int (*brange)[2] = NULL;
+ int brange_len = pdf_array_len(ctx, byte_range)/2;
+ unsigned char *digest = NULL;
+ int digest_len;
+
+ fz_var(in);
+ fz_var(brange);
+
+ if (hexdigest_length < 4)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Bad parameters to pdf_write_digest");
+
+ fz_try(ctx)
+ {
+ int i, res;
+
+ in = fz_stream_from_output(ctx, out);
+
+ brange = fz_calloc(ctx, brange_len, sizeof(*brange));
+ for (i = 0; i < brange_len; i++)
+ {
+ brange[i][0] = pdf_to_int(ctx, pdf_array_get(ctx, byte_range, 2*i));
+ brange[i][1] = pdf_to_int(ctx, pdf_array_get(ctx, byte_range, 2*i+1));
+ }
+
+ digest_len = (hexdigest_length - 2) / 2;
+ digest = fz_malloc(ctx, digest_len);
+ res = pdf_pkcs7_create_digest(ctx, in, brange, brange_len, signer, digest, &digest_len);
+ if (!res)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "pdf_pkcs7_create_digest failed");
+
+ fz_drop_stream(ctx, in);
+ in = NULL;
+
+ fz_seek_output(ctx, out, hexdigest_offset+1, SEEK_SET);
+
+ for (i = 0; i < digest_len; i++)
+ fz_write_printf(ctx, out, "%02x", digest[i]);
+ }
+ fz_always(ctx)
+ {
+ fz_free(ctx, digest);
+ fz_free(ctx, brange);
+ fz_drop_stream(ctx, in);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+}
+
+int pdf_check_signature(fz_context *ctx, pdf_document *doc, pdf_widget *widget, char *ebuf, int ebufsize)
+{
+ int (*byte_range)[2] = NULL;
+ int byte_range_len;
+ char *contents = NULL;
+ int contents_len;
+ int res = 0;
+
+ if (pdf_xref_obj_is_unsaved_signature(doc, ((pdf_annot *)widget)->obj))
+ {
+ fz_strlcpy(ebuf, "Signed but document yet to be saved", ebufsize);
+ if (ebufsize > 0)
+ ebuf[ebufsize-1] = 0;
+ return 0;
+ }
+
+ fz_var(byte_range);
+ fz_var(res);
+ fz_try(ctx)
+ {
+ byte_range_len = pdf_signature_widget_byte_range(ctx, doc, widget, NULL);
+ if (byte_range_len)
+ {
+ byte_range = fz_calloc(ctx, byte_range_len, sizeof(*byte_range));
+ pdf_signature_widget_byte_range(ctx, doc, widget, byte_range);
+ }
+
+ contents_len = pdf_signature_widget_contents(ctx, doc, widget, &contents);
+ if (byte_range && contents)
+ {
+ SignatureError err = pdf_pkcs7_check_digest(ctx, doc->file, contents, contents_len, byte_range, byte_range_len);
+ if (err == SignatureError_Okay)
+ err = pdf_pkcs7_check_certificate(contents, contents_len);
+ switch (err)
+ {
+ case SignatureError_Okay:
+ ebuf[0] = 0;
+ res = 1;
+ break;
+ case SignatureError_NoSignatures:
+ fz_strlcpy(ebuf, "No signatures", ebufsize);
+ break;
+ case SignatureError_NoCertificate:
+ fz_strlcpy(ebuf, "No certificate", ebufsize);
+ break;
+ case SignatureError_DocumentChanged:
+ fz_strlcpy(ebuf, "Document changed since signing", ebufsize);
+ break;
+ case SignatureError_SelfSigned:
+ fz_strlcpy(ebuf, "Self-signed certificate", ebufsize);
+ break;
+ case SignatureError_SelfSignedInChain:
+ fz_strlcpy(ebuf, "Self-signed certificate in chain", ebufsize);
+ break;
+ case SignatureError_NotTrusted:
+ fz_strlcpy(ebuf, "Certificate not trusted", ebufsize);
+ break;
+ default:
+ case SignatureError_Unknown:
+ fz_strlcpy(ebuf, "Unknown error", ebufsize);
+ break;
+ }
+
+ switch (err)
+ {
+ case SignatureError_SelfSigned:
+ case SignatureError_SelfSignedInChain:
+ case SignatureError_NotTrusted:
+ {
+ pdf_pkcs7_designated_name *name = pdf_cert_designated_name(ctx, contents, contents_len);
+ if (name)
+ {
+ int len;
+
+ fz_strlcat(ebuf, ": ", ebufsize);
+ len = strlen(ebuf);
+ pdf_print_designated_name(name, ebuf + len, ebufsize - len);
+ pdf_pkcs7_drop_designated_name(ctx, name);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ res = 0;
+ fz_strlcpy(ebuf, "Not signed", ebufsize);
+ }
+ }
+ fz_always(ctx)
+ {
+ fz_free(ctx, byte_range);
+ }
+ fz_catch(ctx)
+ {
+ res = 0;
+ fz_strlcpy(ebuf, fz_caught_message(ctx), ebufsize);
+ }
+
+ if (ebufsize > 0)
+ ebuf[ebufsize-1] = 0;
+
+ return res;
+}
+
+void pdf_sign_signature(fz_context *ctx, pdf_document *doc, pdf_widget *widget, const char *sigfile, const char *password)
+{
+ pdf_pkcs7_signer *signer = pdf_pkcs7_read_pfx(ctx, sigfile, password);
+ pdf_pkcs7_designated_name *dn = NULL;
+ fz_buffer *fzbuf = NULL;
+
+ fz_try(ctx)
+ {
+ const char *dn_str;
+ pdf_obj *wobj = ((pdf_annot *)widget)->obj;
+ fz_rect rect = fz_empty_rect;
+
+ pdf_signature_set_value(ctx, doc, wobj, signer);
+
+ pdf_to_rect(ctx, pdf_dict_get(ctx, wobj, PDF_NAME_Rect), &rect);
+ /* Create an appearance stream only if the signature is intended to be visible */
+ if (!fz_is_empty_rect(&rect))
+ {
+ dn = pdf_pkcs7_signer_designated_name(ctx, signer);
+ fzbuf = fz_new_buffer(ctx, 256);
+ if (!dn->cn)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Certificate has no common name");
+
+ fz_append_printf(ctx, fzbuf, "cn=%s", dn->cn);
+
+ if (dn->o)
+ fz_append_printf(ctx, fzbuf, ", o=%s", dn->o);
+
+ if (dn->ou)
+ fz_append_printf(ctx, fzbuf, ", ou=%s", dn->ou);
+
+ if (dn->email)
+ fz_append_printf(ctx, fzbuf, ", email=%s", dn->email);
+
+ if (dn->c)
+ fz_append_printf(ctx, fzbuf, ", c=%s", dn->c);
+
+ dn_str = fz_string_from_buffer(ctx, fzbuf);
+ pdf_set_signature_appearance(ctx, doc, (pdf_annot *)widget, dn->cn, dn_str, NULL);
+ }
+ }
+ fz_always(ctx)
+ {
+ pdf_pkcs7_drop_signer(ctx, signer);
+ pdf_pkcs7_drop_designated_name(ctx, dn);
+ fz_drop_buffer(ctx, fzbuf);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+}
+
+int pdf_signatures_supported(fz_context *ctx)
+{
+ return pdf_pkcs7_supported(ctx);
+}
diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c
index bc67f003..0ab76a35 100644
--- a/source/pdf/pdf-write.c
+++ b/source/pdf/pdf-write.c
@@ -2708,7 +2708,7 @@ static void complete_signatures(fz_context *ctx, pdf_document *doc, pdf_write_st
{
xref->unsaved_sigs = usig->next;
pdf_drop_obj(ctx, usig->field);
- pdf_drop_signer(ctx, usig->signer);
+ pdf_pkcs7_drop_signer(ctx, usig->signer);
fz_free(ctx, usig);
}
}
diff --git a/source/pdf/pdf-xref.c b/source/pdf/pdf-xref.c
index 5ff13f55..1dc3b7d8 100644
--- a/source/pdf/pdf-xref.c
+++ b/source/pdf/pdf-xref.c
@@ -59,7 +59,7 @@ static void pdf_drop_xref_sections_imp(fz_context *ctx, pdf_document *doc, pdf_x
{
xref->unsaved_sigs = usig->next;
pdf_drop_obj(ctx, usig->field);
- pdf_drop_signer(ctx, usig->signer);
+ pdf_pkcs7_drop_signer(ctx, usig->signer);
fz_free(ctx, usig);
}
}
@@ -408,7 +408,7 @@ int pdf_xref_is_incremental(fz_context *ctx, pdf_document *doc, int num)
return num < xref->num_objects && sub->table[num].type;
}
-void pdf_xref_store_unsaved_signature(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_signer *signer)
+void pdf_xref_store_unsaved_signature(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_pkcs7_signer *signer)
{
pdf_xref *xref = &doc->xref_sections[0];
pdf_unsaved_sig *unsaved_sig;
@@ -418,7 +418,7 @@ void pdf_xref_store_unsaved_signature(fz_context *ctx, pdf_document *doc, pdf_ob
* saving time */
unsaved_sig = fz_malloc_struct(ctx, pdf_unsaved_sig);
unsaved_sig->field = pdf_keep_obj(ctx, field);
- unsaved_sig->signer = pdf_keep_signer(ctx, signer);
+ unsaved_sig->signer = pdf_pkcs7_keep_signer(ctx, signer);
unsaved_sig->next = NULL;
if (xref->unsaved_sigs_end == NULL)
xref->unsaved_sigs_end = &xref->unsaved_sigs;