diff options
author | Paul Gardiner <paul.gardiner@artifex.com> | 2017-12-20 13:37:41 +0000 |
---|---|---|
committer | Paul Gardiner <paul.gardiner@artifex.com> | 2018-01-19 13:52:25 +0000 |
commit | 7b00d13e09bfe3d09b9f48142974e8cc936d1984 (patch) | |
tree | dd8779213b888691a4e12312986d006e12973624 /source/pdf/pdf-pkcs7.c | |
parent | 55cf67158b926589bee4ea2421b4acc46e6f9844 (diff) | |
download | mupdf-7b00d13e09bfe3d09b9f48142974e8cc936d1984.tar.xz |
Further changes to signature support related to changes in openssl
Reinstate the separate consideration of errors relating to the
certificate trust checking phase.
Remove the key-usage records from the certificate before signature
verification. This is done so that openssl will recognise self
signed cerificates. openssl doesn't consider them as such when
the key usage doesn't include certificate signing.
Diffstat (limited to 'source/pdf/pdf-pkcs7.c')
-rw-r--r-- | source/pdf/pdf-pkcs7.c | 89 |
1 files changed, 69 insertions, 20 deletions
diff --git a/source/pdf/pdf-pkcs7.c b/source/pdf/pdf-pkcs7.c index 2f3382bd..4526d5e9 100644 --- a/source/pdf/pdf-pkcs7.c +++ b/source/pdf/pdf-pkcs7.c @@ -247,9 +247,33 @@ static int verify_callback(int ok, X509_STORE_CTX *ctx) return ok; } +/* Get the certificates from a PKCS7 object */ +static STACK_OF(X509) *pk7_certs(PKCS7 *pk7) +{ + if (pk7 == NULL) + return NULL; + + if (PKCS7_type_is_signed(pk7)) + return pk7->d.sign->cert; + else if (PKCS7_type_is_signedAndEnveloped(pk7)) + return pk7->d.signed_and_enveloped->cert; + else + return NULL; +} + +/* Get the signing certificate from a PKCS7 object */ +static X509 *pk7_signer(PKCS7 *pk7, 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) { - PKCS7_SIGNER_INFO *si; BIO *p7bio=NULL; char readbuf[1024*4]; int res = 1; @@ -297,15 +321,51 @@ 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; - si = sk_PKCS7_SIGNER_INFO_value(sk, i); + int ctx_err; + PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(sk, i); + X509 *cert = pk7_signer(p7, si); + if (cert == NULL) + { + res = 0; + fz_strlcpy(ebuf, "Certificate missing", ebufsize); + goto exit; + } + + /* Acrobat reader creates self-signed certificates that don't list + * certificate signing within the key usage parameters. openssl does + * not recognise those as self signed. We work around this by removing + * the key usage parameters before the verification check */ + { + int i = X509_get_ext_by_NID(cert, NID_key_usage, -1); + if (i >= 0) + { + X509_EXTENSION *ext = X509_get_ext(cert, i); + X509_delete_ext(cert, i); + X509_EXTENSION_free(ext); + } + } + rc = PKCS7_dataVerify(cert_store, ctx, p7bio, p7, si); - if (rc == 0) + ctx_err = X509_STORE_CTX_get_error(ctx); + + if (rc <= 0 || ctx_err != X509_V_OK) { - unsigned long err = ERR_get_error(); - ERR_error_string_n(err, ebuf, ebufsize); - strncat(ebuf, ":", ebufsize); - err = X509_STORE_CTX_get_error(ctx); - strncat(ebuf, X509_verify_cert_error_string(err), ebufsize); + 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); + } + res = 0; goto exit; } @@ -328,7 +388,6 @@ static int verify_sig(char *sig, int sig_len, char *file, int (*byte_range)[2], BIO *bdata = NULL; BIO *bsegs = NULL; STACK_OF(X509) *certs = NULL; - int t; int res = 0; bsig = BIO_new_mem_buf(sig, sig_len); @@ -354,17 +413,7 @@ static int verify_sig(char *sig, int sig_len, char *file, int (*byte_range)[2], if (pk7cert == NULL) goto exit; - t = OBJ_obj2nid(pk7cert->type); - switch (t) - { - case NID_pkcs7_signed: - case NID_pkcs7_signedAndEnveloped: - certs = pk7cert->d.sign->cert; - break; - - default: - break; - } + certs = pk7_certs(pk7cert); st = X509_STORE_new(); if (st == NULL) |