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. :)
Adding Andre as he appear to be the one developing the certificate related code.
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.
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)
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. :)
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.
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?
-- 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.