summaryrefslogtreecommitdiff
path: root/source/pdf
diff options
context:
space:
mode:
authorPaul Gardiner <paul.gardiner@artifex.com>2018-01-10 13:36:05 +0000
committerPaul Gardiner <paul.gardiner@artifex.com>2018-02-02 12:36:13 +0000
commit7c94151aa9f39ea70268ecb4806b726372cae753 (patch)
tree34e4db342c54d5765a20deea1c426d94bfbb546e /source/pdf
parentb105ae5371549dce1b7e3d39fe130307f50d908a (diff)
downloadmupdf-7c94151aa9f39ea70268ecb4806b726372cae753.tar.xz
Signature support: separate the checkin of trust and digest.
The openssl function we were using checked both trust and the digest. Annoyingly, it checked trust first, so some trickery had to be used to check the digest for self-signed certificates. Now we make use of parts of the functions we were calling to provide the two parts of the check as separate functions.
Diffstat (limited to 'source/pdf')
-rw-r--r--source/pdf/pdf-pkcs7.c159
1 files changed, 105 insertions, 54 deletions
diff --git a/source/pdf/pdf-pkcs7.c b/source/pdf/pdf-pkcs7.c
index 297b564b..a0f7ff10 100644
--- a/source/pdf/pdf-pkcs7.c
+++ b/source/pdf/pdf-pkcs7.c
@@ -69,6 +69,7 @@ static const char AdobeCA_p7c[] = {
#include "openssl/bio.h"
#include "openssl/asn1.h"
#include "openssl/x509.h"
+#include "openssl/x509v3.h"
#include "openssl/err.h"
#include "openssl/objects.h"
#include "openssl/pem.h"
@@ -318,15 +319,6 @@ static int verify_callback(int ok, X509_STORE_CTX *ctx)
ok = 1;
break;
- case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
- case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
- /*
- In this case, don't reset err to X509_V_OK, so that it can be reported,
- although we do return 1, so that the digest will still be checked
- */
- ok = 1;
- break;
-
default:
break;
}
@@ -337,7 +329,7 @@ static int verify_callback(int ok, X509_STORE_CTX *ctx)
/* Get the certificates from a PKCS7 object */
static STACK_OF(X509) *pk7_certs(PKCS7 *pk7)
{
- if (pk7 == NULL)
+ if (pk7 == NULL || pk7->d.ptr == NULL)
return NULL;
if (PKCS7_type_is_signed(pk7))
@@ -349,48 +341,32 @@ static STACK_OF(X509) *pk7_certs(PKCS7 *pk7)
}
/* Get the signing certificate from a PKCS7 object */
-static X509 *pk7_signer(PKCS7 *pk7, PKCS7_SIGNER_INFO *si)
+static X509 *pk7_signer(STACK_OF(X509) *certs, PKCS7_SIGNER_INFO *si)
{
PKCS7_ISSUER_AND_SERIAL *ias = si->issuer_and_serial;
- STACK_OF(X509) *certs = pk7_certs(pk7);
if (certs == NULL)
return NULL;
return X509_find_by_issuer_and_serial(certs, ias->issuer, ias->serial);
}
-static int pk7_verify(X509_STORE *cert_store, PKCS7 *p7, BIO *detached, char *ebuf, int ebufsize)
+static int pk7_verify_sig(PKCS7 *p7, BIO *detached, char *ebuf, int ebufsize)
{
BIO *p7bio=NULL;
char readbuf[1024*4];
int res = 1;
int i;
STACK_OF(PKCS7_SIGNER_INFO) *sk;
- X509_STORE_CTX *ctx;
ebuf[0] = 0;
- ctx = X509_STORE_CTX_new();
-
- OpenSSL_add_all_algorithms();
-
- if (!EVP_add_digest(EVP_md5()) ||
- !EVP_add_digest(EVP_sha1()) ||
- !ERR_load_crypto_strings())
- goto exit;
-
-
ERR_clear_error();
- ERR_load_BIO_strings();
- ERR_load_crypto_strings();
- ERR_load_X509_strings();
-
- X509_STORE_set_verify_cb_func(cert_store, verify_callback);
p7bio = PKCS7_dataInit(p7, detached);
if (!p7bio)
goto exit;
+
/* We now have to 'read' from p7bio to calculate digests etc. */
while (BIO_read(p7bio, readbuf, sizeof(readbuf)) > 0)
;
@@ -408,9 +384,63 @@ static int pk7_verify(X509_STORE *cert_store, PKCS7 *p7, BIO *detached, char *eb
for (i=0; i<sk_PKCS7_SIGNER_INFO_num(sk); i++)
{
int rc;
+ PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(sk, i);
+ X509 *x509 = pk7_signer(pk7_certs(p7), si);
+
+ /* were we able to find the cert in passed to us */
+ if (x509 == NULL)
+ {
+ res = 0;
+ fz_strlcpy(ebuf, "No signatures", ebufsize);
+ goto exit;
+ }
+
+ rc = PKCS7_signatureVerify(p7bio, p7, si, x509);
+ if (rc <= 0)
+ {
+ ERR_error_string_n(ERR_get_error(), ebuf, ebufsize);
+ res = 0;
+ goto exit;
+ }
+ }
+
+exit:
+ ERR_free_strings();
+
+ return res;
+}
+
+static int pk7_verify_cert(X509_STORE *cert_store, PKCS7 *p7, char *ebuf, int ebufsize)
+{
+ int res = 1;
+ int i;
+ STACK_OF(PKCS7_SIGNER_INFO) *sk;
+ X509_STORE_CTX *ctx;
+
+ ebuf[0] = 0;
+
+ ctx = X509_STORE_CTX_new();
+
+ ERR_clear_error();
+
+ X509_STORE_set_verify_cb_func(cert_store, verify_callback);
+
+ /* We can now verify signatures */
+ sk = PKCS7_get_signer_info(p7);
+ if (sk == NULL)
+ {
+ /* there are no signatures on this data */
+ res = 0;
+ fz_strlcpy(ebuf, "No signatures", ebufsize);
+ goto exit;
+ }
+
+ for (i=0; i<sk_PKCS7_SIGNER_INFO_num(sk); i++)
+ {
int ctx_err;
PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(sk, i);
- X509 *cert = pk7_signer(p7, si);
+ STACK_OF(X509) *certs = pk7_certs(p7);
+ X509 *cert = pk7_signer(certs, si);
if (cert == NULL)
{
res = 0;
@@ -432,26 +462,24 @@ static int pk7_verify(X509_STORE *cert_store, PKCS7 *p7, BIO *detached, char *eb
}
}
- rc = PKCS7_dataVerify(cert_store, ctx, p7bio, p7, si);
- ctx_err = X509_STORE_CTX_get_error(ctx);
+ if (!X509_STORE_CTX_init(ctx, cert_store, cert, certs))
+ {
+ res = 0;
+ PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, ERR_R_X509_LIB);
+ goto exit;
+ }
+
+ X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_SMIME_SIGN);
- if (rc <= 0 || ctx_err != X509_V_OK)
+ X509_verify_cert(ctx);
+ X509_STORE_CTX_cleanup(ctx);
+ ctx_err = X509_STORE_CTX_get_error(ctx);
+ if (ctx_err != X509_V_OK)
{
- if (rc <= 0)
- {
- /* dataVerify failed */
- ERR_error_string_n(ERR_get_error(), ebuf, ebufsize);
- }
- else
- {
- int used;
- /* dataVerify passed, but only because our verify callback
- skipped over some problems during the certificate trust
- checking stage. */
- fz_snprintf(ebuf, ebufsize, "%s(%d): ", X509_verify_cert_error_string(ctx_err), ctx_err);
- used = strlen(ebuf);
- X509_NAME_oneline(X509_get_subject_name(cert), ebuf + used, ebufsize - used);
- }
+ int used;
+ fz_snprintf(ebuf, ebufsize, "%s(%d): ", X509_verify_cert_error_string(ctx_err), ctx_err);
+ used = strlen(ebuf);
+ X509_NAME_oneline(X509_get_subject_name(cert), ebuf + used, ebufsize - used);
res = 0;
goto exit;
@@ -468,10 +496,7 @@ exit:
static int verify_sig(fz_context *ctx, fz_stream *stm, char *sig, int sig_len, int (*byte_range)[2], int byte_range_len, char *ebuf, int ebufsize)
{
PKCS7 *pk7sig = NULL;
- PKCS7 *pk7cert = NULL;
- X509_STORE *st = NULL;
BIO *bsig = NULL;
- BIO *bcert = NULL;
BIO *bdata = NULL;
BIO *bsegs = NULL;
STACK_OF(X509) *certs = NULL;
@@ -493,6 +518,32 @@ static int verify_sig(fz_context *ctx, fz_stream *stm, char *sig, int sig_len, i
BIO_set_next(bsegs, bdata);
BIO_set_segments(bsegs, byte_range, byte_range_len);
+ res = pk7_verify_sig(pk7sig, bsegs, ebuf, ebufsize);
+
+exit:
+ BIO_free(bsig);
+ BIO_free(bdata);
+ BIO_free(bsegs);
+ PKCS7_free(pk7sig);
+
+ return res;
+}
+
+static int verify_cert(fz_context *ctx, char *sig, int sig_len, char *ebuf, int ebufsize)
+{
+ PKCS7 *pk7sig = NULL;
+ PKCS7 *pk7cert = NULL;
+ X509_STORE *st = NULL;
+ BIO *bsig = NULL;
+ BIO *bcert = NULL;
+ STACK_OF(X509) *certs = NULL;
+ int res = 0;
+
+ bsig = BIO_new_mem_buf(sig, sig_len);
+ pk7sig = d2i_PKCS7_bio(bsig, NULL);
+ if (pk7sig == NULL)
+ goto exit;
+
/* Find the certificates in the pk7 file */
bcert = BIO_new_mem_buf((void*)AdobeCA_p7c, sizeof AdobeCA_p7c);
pk7cert = d2i_PKCS7_bio(bcert, NULL);
@@ -517,12 +568,10 @@ static int verify_sig(fz_context *ctx, fz_stream *stm, char *sig, int sig_len, i
}
}
- res = pk7_verify(st, pk7sig, bsegs, ebuf, ebufsize);
+ res = pk7_verify_cert(st, pk7sig, ebuf, ebufsize);
exit:
BIO_free(bsig);
- BIO_free(bdata);
- BIO_free(bsegs);
BIO_free(bcert);
PKCS7_free(pk7sig);
PKCS7_free(pk7cert);
@@ -878,6 +927,8 @@ int pdf_check_signature(fz_context *ctx, pdf_document *doc, pdf_widget *widget,
if (byte_range && contents)
{
res = verify_sig(ctx, doc->file, contents, contents_len, byte_range, byte_range_len, ebuf, ebufsize);
+ if (res)
+ res = verify_cert(ctx, contents, contents_len, ebuf, ebufsize);
}
else
{