summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/pdf/pdf-pkcs7.c89
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)