dealfonso / sapp

Simple and Agnostic PDF Document Parser in PHP - sign PDF docs using PHP
GNU Lesser General Public License v3.0
110 stars 29 forks source link

Issue with Digital Signature Validation #46

Closed Abdulazeezvp closed 1 year ago

Abdulazeezvp commented 1 year ago

I have recently encountered an issue with the digital signature validation of file.pdf. Upon checking the signature information, I found that there is a "Digest Mismatch" error, which indicates that the computed digest of the signed ranges does not match the actual digest of the file.

Signature Info of: file.pdf Signature #1:

dealfonso commented 1 year ago

Hi, could you please attach the documents involved (the original and the signed one)

Abdulazeezvp commented 1 year ago

original document(before signing) signed pdf

I attempted to create a sample PDF, but in the actual scenario, I am using the DOMPDF library to generate the PDF.

here is minimal version of my code


$config = array(
    'private_key_bits' => 2048,
    'private_key_type' => OPENSSL_KEYTYPE_RSA,
    'digest_alg' => 'sha256'
);
$dn = array(
    "countryName" => "IN",
    "stateOrProvinceName" => "Kerala",
    "localityName" => "Kochi",
    "organizationName" => "Test",
    "organizationalUnitName" => "Test",
    "commonName" => "test",
);
$algo=array(
    "digest_alg" => "sha256",
);

$privateKey = openssl_pkey_new($config);
$csr = openssl_csr_new($dn, $privateKey,$config);

$caKey = openssl_pkey_new(array(
    'private_key_bits' => 2048,
    'private_key_type' => OPENSSL_KEYTYPE_RSA
));

$caCsr = openssl_csr_new($dn, $privateKey, array(
    'digest_alg' => 'sha256',
    'x509_extensions' => 'v3_ca'
));

$caCert = openssl_csr_sign($caCsr, null, $privateKey, 365, array(
    'digest_alg' => 'sha256',
    'x509_extensions' => 'v3_ca'
));

$certificate = openssl_csr_sign($csr, $caCert, $privateKey, 365,$algo,time());

$file_content = file_get_contents('sample.pdf');

$obj = PDFDoc::from_string($file_content);

if ($obj === false){
    echo "Failed to parse file";
    exit;
}
else {
    if (!$obj->set_signature_certificate(array('cert'=>$certificate,'pkey'=>$privateKey), null)) {
        echo "not a valid certificate";
        exit;
    } else {
        $docsigned = $obj->to_pdf_file_s();
        if ($docsigned === false){

            echo "could not sign document";exit;   
        }
        else{
            $newObj= PDFDoc::from_string($docsigned);

            echo "PDF signed successfully!\n";
            header('Content-Type: application/pdf');
            header('Content-Disposition: attachment; filename="file.pdf"');
            echo $docsigned;
        }

    }
}
parallels999 commented 1 year ago

I found that there is a "Digest Mismatch" error

I can't find that, it comes out correct, just The certificate is not trusted because the issuer certificate is unknown

Abdulazeezvp commented 1 year ago

I got response mentioned, in linux pdfsig command.

parallels999 commented 1 year ago

https://bugs.freedesktop.org/show_bug.cgi?id=99365

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. :)

The problem seems the same as I mentioned initially, the signature is correct

just The certificate is not trusted because the issuer certificate is unknown

https://fossies.org/linux/poppler/utils/pdfsig.cc

Abdulazeezvp commented 1 year ago

Ok, thanks for helping.