#include "mupdf/fitz.h" #include "mupdf/pdf.h" #include "mupdf/helpers/pkcs7-check.h" char *pdf_signature_error_description(enum pdf_signature_error err) { switch (err) { case PDF_SIGNATURE_ERROR_OKAY: return ""; case PDF_SIGNATURE_ERROR_NO_SIGNATURES: return "No signatures."; case PDF_SIGNATURE_ERROR_NO_CERTIFICATE: return "No certificate."; case PDF_SIGNATURE_ERROR_DIGEST_FAILURE: return "Signature invalidated by change to document."; case PDF_SIGNATURE_ERROR_SELF_SIGNED: return "Self-signed certificate."; case PDF_SIGNATURE_ERROR_SELF_SIGNED_IN_CHAIN: return "Self-signed certificate in chain."; case PDF_SIGNATURE_ERROR_NOT_TRUSTED: return "Certificate not trusted."; default: case PDF_SIGNATURE_ERROR_UNKNOWN: return "Unknown error."; } } #ifdef HAVE_LIBCRYPTO #include "mupdf/helpers/pkcs7-openssl.h" #include static void pdf_format_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_signature_designated_name(fz_context *ctx, pdf_document *doc, pdf_obj *signature, char *buf, int buflen) { char *contents = NULL; int contents_len = pdf_signature_contents(ctx, doc, signature, &contents); pdf_pkcs7_designated_name *name = NULL; fz_try(ctx) { name = pkcs7_openssl_designated_name(ctx, contents, contents_len); if (name) { pdf_format_designated_name(name, buf, buflen); pkcs7_openssl_drop_designated_name(ctx, name); } else if (buflen > 0) buf[0] = '\0'; } fz_always(ctx) fz_free(ctx, contents); fz_catch(ctx) fz_rethrow(ctx); } enum pdf_signature_error pdf_check_digest(fz_context *ctx, pdf_document *doc, pdf_obj *signature) { enum pdf_signature_error err; fz_stream *bytes = NULL; char *contents = NULL; int contents_len = pdf_signature_contents(ctx, doc, signature, &contents); fz_var(err); fz_var(bytes); fz_try(ctx) { bytes = pdf_signature_hash_bytes(ctx, doc, signature); err = pkcs7_openssl_check_digest(ctx, bytes, contents, contents_len); } fz_always(ctx) { fz_drop_stream(ctx, bytes); fz_free(ctx, contents); } fz_catch(ctx) { fz_rethrow(ctx); } return err; } enum pdf_signature_error pdf_check_certificate(fz_context *ctx, pdf_document *doc, pdf_obj *signature) { char *contents = NULL; int contents_len = pdf_signature_contents(ctx, doc, signature, &contents); enum pdf_signature_error result; fz_try(ctx) result = pkcs7_openssl_check_certificate(contents, contents_len); fz_always(ctx) fz_free(ctx, contents); fz_catch(ctx) fz_rethrow(ctx); return result; } int pdf_check_signature(fz_context *ctx, pdf_document *doc, pdf_obj *signature, char *ebuf, int ebufsize) { int res = 0; if (pdf_xref_obj_is_unsaved_signature(doc, signature)) { fz_strlcpy(ebuf, "Signed but document yet to be saved.", ebufsize); if (ebufsize > 0) ebuf[ebufsize-1] = 0; return 0; } fz_var(res); fz_try(ctx) { if (pdf_signature_is_signed(ctx, doc, signature)) { enum pdf_signature_error err; err = pdf_check_digest(ctx, doc, signature); if (err == PDF_SIGNATURE_ERROR_OKAY) err = pdf_check_certificate(ctx, doc, signature); fz_strlcpy(ebuf, pdf_signature_error_description(err), ebufsize); res = (err == PDF_SIGNATURE_ERROR_OKAY); switch (err) { case PDF_SIGNATURE_ERROR_SELF_SIGNED: case PDF_SIGNATURE_ERROR_SELF_SIGNED_IN_CHAIN: case PDF_SIGNATURE_ERROR_NOT_TRUSTED: { int len; fz_strlcat(ebuf, " (", ebufsize); len = strlen(ebuf); pdf_signature_designated_name(ctx, doc, signature, ebuf + len, ebufsize - len); fz_strlcat(ebuf, ")", ebufsize); } break; default: break; } } else { res = 0; fz_strlcpy(ebuf, "Not signed.", ebufsize); } } fz_catch(ctx) { res = 0; fz_strlcpy(ebuf, fz_caught_message(ctx), ebufsize); } if (ebufsize > 0) ebuf[ebufsize-1] = 0; return res; } #else void pdf_signature_designated_name(fz_context *ctx, pdf_document *doc, pdf_obj *signature, char *buf, int buflen) { fz_throw(ctx, FZ_ERROR_GENERIC, "No OpenSSL support."); } enum pdf_signature_error pdf_check_digest(fz_context *ctx, pdf_document *doc, pdf_obj *signature) { fz_throw(ctx, FZ_ERROR_GENERIC, "No OpenSSL support."); return 0; } enum pdf_signature_error pdf_check_certificate(fz_context *ctx, pdf_document *doc, pdf_obj *signature) { fz_throw(ctx, FZ_ERROR_GENERIC, "No OpenSSL support."); return 0; } int pdf_check_signature(fz_context *ctx, pdf_document *doc, pdf_obj *signature, char *ebuf, int ebufsize) { fz_strlcpy(ebuf, "No digital signing support in this build", ebufsize); return 0; } #endif