203 lines
4.8 KiB
C
203 lines
4.8 KiB
C
|
#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 <string.h>
|
||
|
|
||
|
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
|