diff options
author | Paul Gardiner <paul.gardiner@artifex.com> | 2017-12-22 15:12:31 +0000 |
---|---|---|
committer | Paul Gardiner <paul.gardiner@artifex.com> | 2018-02-02 12:38:36 +0000 |
commit | 0b04079f5057ba6c7726bd14b61abed9fde1957a (patch) | |
tree | 72893a36a9b86490566c9469071724a52b4060d9 /source/helpers/pkcs7/pkcs7-check.c | |
parent | 9b6b7ac94658d65204fab0146907ac8c6af287bb (diff) | |
download | mupdf-0b04079f5057ba6c7726bd14b61abed9fde1957a.tar.xz |
Signature support: decouple mupdf from the pkcs7 implementation
The mupdf build included an implimentation of the pkcs7 functions that
are needed for signing documents and verifying signatures, the
implementation being either an openssl-based one, or a stub that returned
errors. This commit removes the pkcs7 functions from the main mupdf
library.
For the sake of verification, there wasn't really a need for the pkcs7
functions to be part of mupdf. It was only the checking function that used
them. The checking function is now provided as a helper, outside of the
main build. The openssl-based pkcs7 functions area also supplied as a
helper. Users wishing to verify signatures can either use the checking
function directly, or use the source on which to base their own.
Document signing requires more integration between mupdf and pkcs7
because part of the process is performed at time of signing and part when
saving the document. Mupdf already had a pdf_pkcs7_signer object that
kept information between the two phases. That object has now been extended
to include the pkcs7 functions involved in signing, and the signing
function now requires such an object, rather than a file path to a
certificate. The openssl-based pkcs7 helper provides a function that, given
the path to a certificate, will return a pdf_pkcs7_signer object.
The intention is that different implementations can be produced for
different platforms, based on cryptographic routines built into the
operationg system. In each case, for the sake of document signing, the
routines would be wrapped up as a pdf_pkcs7_signer object.
Diffstat (limited to 'source/helpers/pkcs7/pkcs7-check.c')
-rw-r--r-- | source/helpers/pkcs7/pkcs7-check.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/source/helpers/pkcs7/pkcs7-check.c b/source/helpers/pkcs7/pkcs7-check.c new file mode 100644 index 00000000..72b6af90 --- /dev/null +++ b/source/helpers/pkcs7/pkcs7-check.c @@ -0,0 +1,128 @@ +#include "mupdf/fitz.h" +#include "mupdf/pdf.h" +#include "mupdf/helpers/pkcs7-openssl.h" +#include "mupdf/helpers/pkcs7-check.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); +} + +int pdf_check_signature(fz_context *ctx, pdf_document *doc, pdf_widget *widget, char *ebuf, int ebufsize) +{ + fz_stream *bytes = NULL; + 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(bytes); + fz_var(res); + fz_try(ctx) + { + contents_len = pdf_signature_widget_contents(ctx, doc, widget, &contents); + if (contents) + { + SignatureError err; + + bytes = pdf_signature_widget_hash_bytes(ctx, doc, widget); + err = pkcs7_openssl_check_digest(ctx, bytes, contents, contents_len); + if (err == SignatureError_Okay) + err = pkcs7_openssl_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 = pkcs7_openssl_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); + pkcs7_opensll_drop_designated_name(ctx, name); + } + } + break; + default: + break; + } + } + else + { + res = 0; + fz_strlcpy(ebuf, "Not signed", ebufsize); + } + } + fz_always(ctx) + { + fz_drop_stream(ctx, bytes); + } + fz_catch(ctx) + { + res = 0; + fz_strlcpy(ebuf, fz_caught_message(ctx), ebufsize); + } + + if (ebufsize > 0) + ebuf[ebufsize-1] = 0; + + return res; +} |