Bug 99365

Summary: Certificate chain from PDF digital signature back to trusted root certificate not verified?
Product: poppler Reporter: Sebastian Rasmussen <sebras>
Component: generalAssignee: poppler-bugs <poppler-bugs>
Status: RESOLVED MOVED QA Contact:
Severity: normal    
Priority: medium CC: aguerreiro1985, brian, sebras
Version: unspecified   
Hardware: All   
OS: All   
Whiteboard:
i915 platform: i915 features:

Description Sebastian Rasmussen 2017-01-11 18:04:15 UTC
I believe that the full certificate chain back to a trusted root certificate is not verified when attempting to verify digital signatures in PDFs.

SignatureHandler::init_nss() initializes NSS to point to my root
certficate database in my firefox profile or if not available
(it is available) /etc/pki/nssdb (which is unpopoulated on my machine).

I believe that the idea is that this database of root certificates
will be used when verifying the chain of certificates in digital signatures.

I downloaded http://blogs.adobe.com/security/SampleSignedPDFDocument.pdf
and then ran pdfsig (compiled from git HEAD currently at c301f6c6) like so:

./pdfsig-original ./SampleSignedPDFDocument.pdf
Digital Signature Info of:./SampleSignedPDFDocument.pdf
Signature #1:
  - Signer Certificate Common Name: John B Harris
  - Signing Time: Jul 16 2009 16:47:47
  - Signature Validation: Signature is Valid.
  - Certificate Validation: Certificate has Expired

The mesage "Signature is Valid" implies that the chain of certificates
has all been checked. However if I replace the call to NSS_Init() with
a call that explicitlydisables any preinitialized database like so:

diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
index 15c9321c..4be4a140 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -91,16 +91,9 @@ GooString *SignatureHandler::getDefaultFirefoxCertDB_Linux()
  */
 void SignatureHandler::init_nss() 
 {
-  GooString *certDBPath = getDefaultFirefoxCertDB_Linux();
-  if (certDBPath == NULL) {
-    NSS_Init("sql:/etc/pki/nssdb");
-  } else {
-    NSS_Init(certDBPath->getCString());
-  }
+  NSS_NoDB_Init("");
   //Make sure NSS root certificates module is loaded
   SECMOD_AddNewModule("Root Certs", "libnssckbi.so", 0, 0);
-
-  delete certDBPath;
 }
 
 
And then recompile and rerun pdfsig I get the same message as above:

./pdfsig-changed ./SampleSignedPDFDocument.pdf
Digital Signature Info of: ./SampleSignedPDFDocument.pdf
Signature #1:
  - Signer Certificate Common Name: John B Harris
  - Signing Time: Jul 16 2009 16:47:47
  - Signature Validation: Signature is Valid.
  - Certificate Validation: Certificate has Expired

Which again seems to claim that the chain of certificates is valid.
How can that be when there are no trusted root certificates in the database?

This appears to be corroborated by the comment preceeding the function
NSS_CMSSignerInfo_Verify() which SignatureHandler later calls to do the
verification:

"Just verifies the signature. The assumption is that verification of
the certificate is done already", see
https://hg.mozilla.org/projects/nss/file/tip/lib/smime/cmssiginfo.c#l310

I believe that the intent with the poppler code is to verify
the entire certificate chain (why else bother to add the firefox
root certificate database?), but I don't think that is what is happening.

Unfortunately I'm not yet well versed in this code to figure out
how to fix this, hence there is no patch attached fixing this issue.
Maybe the decision is to be happy that the certificate is self-consistent
and that the digest is matching, etc. but to ignore that the _chain_ of
certificates is never checked, however in that case I'd suggest mentioning
this clearly, e.g. "Signature is Valid (chain back to root certificate not checked)".

Oh, and of course any UI that uses SignatureHandler is equally affected
as pdfsig, but I find reporting issued using command-line tools easier. :)
Comment 1 Sebastian Rasmussen 2017-01-11 18:33:44 UTC
Adding Andre as he appear to be the one developing the certificate related code.
Comment 2 Albert Astals Cid 2017-01-11 22:57:59 UTC
Having a look at this

enum SignatureValidationStatus
{
  SIGNATURE_VALID,
  SIGNATURE_INVALID,
  SIGNATURE_DIGEST_MISMATCH,
  SIGNATURE_DECODING_ERROR,
  SIGNATURE_GENERIC_ERROR,
  SIGNATURE_NOT_FOUND,
  SIGNATURE_NOT_VERIFIED
};

enum CertificateValidationStatus
{
  CERTIFICATE_TRUSTED,
  CERTIFICATE_UNTRUSTED_ISSUER,
  CERTIFICATE_UNKNOWN_ISSUER,
  CERTIFICATE_REVOKED,
  CERTIFICATE_EXPIRED,
  CERTIFICATE_GENERIC_ERROR,
  CERTIFICATE_NOT_VERIFIED
};

I don't think signature validation has anything to do with the certificates having been checked, I'd say certificate validation is what would give that information.

I.e. valid signature is just saying "yeah this is a signature that seems to be from this guy", whether you trust that guy or not would be part of certificate trustness, that since in this case it's expired doesn't happen and that's why you get the same result whether you initialize the certificate database or not.

This is my understanding, OTOH i did not write the code so I may be totally wrong.
Comment 3 Andre Guerreiro 2017-01-12 14:04:32 UTC
There are indeed 2 different validations happening here:
1- Verification of the cryptographic signature in a strict sense
2- Certificate verification: which includes validity checking and making sure that the certificate chain ends in a trusted root.

Maybe we can change the output string of pdfsig for the 1st validation to something more specific if people find the wording to be misleading:
"Signature Validation: the document was not modified since the document was signed"

Additionally we could output a "global" validation result for each signature which would have 3 possible values: Valid, Invalid or has Issues (when the certificate is not valid or wasn't even verified).
This seems to be the approach taken by Adobe Reader for the signature status icons (Green check, Red Cross, Question Mark)
Comment 4 Sebastian Rasmussen 2017-01-15 19:28:56 UTC
Thanks for the explanations of where I misunderstood what's happening.
Sorry for the unnecessary noise.

> Maybe we can change the output string of pdfsig for the 1st validation to
> something more specific if people find the wording to be misleading:
> "Signature Validation: the document was not modified since the document was
> signed"

There is alos "Digest mismatch" though, which also says something about whether the document was been modified.

As I understand it you basically have three booleans:

1. does the digest for the file match that in the signature dictionary?
2. does the signature in the dictionary sign the digest?
3. is the signature trusted?

And to lessen the confusion maybe these three cases should attempt to
not use overlapping terminology. I'm new to this certificate validation
things though, so maybe it's just me being confused because I'm not yet
clued in on the details. :)
Comment 5 Luiz Angelo Daros de Luca 2017-03-14 21:24:39 UTC
Hello,

I also got this problem with pdfsig v0.52.0.

It seems that pdfsig simply passes to NSS the signer certificate and ask "is it valid?"

The problem is that, normally, NSS cannot verify all the chain from the (imported) root CA to the signer certificate because it misses all the intermediate CA. If I manually import all intermediate CA into firefox, pdfsig can verify the certificate correctly. However, it is not expected that the user must import intermediate CA before checking a certificate.

A PDF file must contain all the certificate chain from the signer certificate (first) until the last CA before root CA. It seems that pdfsig is not passing these intermediate certificates to NSS.

I never used NSS but it must import all intermediate CA into NSS session as an non-root CA.
Comment 6 Andre Guerreiro 2017-03-15 11:06:59 UTC
Hello Luiz,

pdfsig is indeed considering the intermediate CA certificates included in the PDF.
I think you may be experiencing a different issue maybe related to the specific certificates.

Can you share a PDF file so I can investigate this further?
Comment 7 GitLab Migration User 2018-08-21 11:10:15 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/poppler/poppler/issues/546.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.