diff options
author | Paul Gardiner <paul.gardiner@artifex.com> | 2018-01-19 12:14:20 +0000 |
---|---|---|
committer | Paul Gardiner <paul.gardiner@artifex.com> | 2018-02-02 12:36:13 +0000 |
commit | 37e3d2aac1a3493171b28aa5c7344833aa5a8303 (patch) | |
tree | efb2c334219cbdfd09a4920cb9cbea10813e6fdc | |
parent | 1ebb2db0aaa6b5212152dd0f32d781fa81b6bcaa (diff) | |
download | mupdf-37e3d2aac1a3493171b28aa5c7344833aa5a8303.tar.xz |
Signature support: separate pkcs7 specifics into a separate file.
Previously, pdf-pkcs7.c contained mishmash of functions required
for creating and checking signatures, with no separation between
the parts relating to pdf and those relating to pkcs7. This
commit introduces pdf_signature.c which contains the pdf
specifics, leaving pdf-pkcs7.c to be purely pkcs7 functions.
This should more easily allow the use of pkcs7 solutions other
than openssl. The pkcs7 api is declared in pdf-pkcs7.h. It is
entirely free of mupdf specifics, other than using an fz_stream
to specify the bytes to be hashed.
-rw-r--r-- | include/mupdf/pdf.h | 2 | ||||
-rw-r--r-- | include/mupdf/pdf/crypt.h | 30 | ||||
-rw-r--r-- | include/mupdf/pdf/document.h | 4 | ||||
-rw-r--r-- | include/mupdf/pdf/field.h | 2 | ||||
-rw-r--r-- | include/mupdf/pdf/pdf-pkcs7.h | 56 | ||||
-rw-r--r-- | include/mupdf/pdf/xref.h | 2 | ||||
-rw-r--r-- | platform/win32/libmupdf.vcproj | 8 | ||||
-rw-r--r-- | source/pdf/pdf-form.c | 2 | ||||
-rw-r--r-- | source/pdf/pdf-pkcs7.c | 389 | ||||
-rw-r--r-- | source/pdf/pdf-signature.c | 243 | ||||
-rw-r--r-- | source/pdf/pdf-write.c | 2 | ||||
-rw-r--r-- | source/pdf/pdf-xref.c | 6 |
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; |