Closed malamalca closed 1 year ago
Why dont just use Vanilla JS for all the process avoiding SAPP?
Hi,
@malamalca do you have a library to get an arbitrary pkcs7 signature using javascript in a browser? I find that ASN1/pkcs7 is also PHP in the server.
@angeljqv do you have an example of how to sign PDF documents using javascript in a browser? I'd be very grateful if you could show us an example (I have been searching for it for a long time, and I reached to the conclusion that I need an external application; e.g. a java applet).
With forge
Look at this signing example: xades signing
Also: signpdf
PAdES compliant signatures To produce PAdES compliant signatures, the ETSI Signature Dictionary SubFilter value must be ETSI.CAdES.detached instead of the standard Adobe value. That's where the Signer kicks in. Given a PDF and a P12 certificate a signature is generated in detached mode and is replaced in the placeholder. This is best demonstrated in the tests.
Dependencies node-forge is used for working with signatures. PDFKit is used in the tests for generating a PDF with a signature placeholder.
@dealfonso I intended to generate ASN1/pkcs7 packet with php, not with javascript. Javascript only generates signature of a hash and sends it back to server. Began the implementation on library mentioned above, did not finish it yet.
@angeljqv The signature is not a problem. Signing pdf with that signature on client side is.
my problem is signing anything in the browser because I could not find a way to access to the certificate store, except from using a java applet or an external application.
I am signing XML hashes on client side with hwcrypto.js
@malamalca just extend SAPP and override the functions to do what you want Example https://github.com/dealfonso/sapp/issues/36#issuecomment-1296953323
With forge
@dealfonso comments? thoughts?
Hi,
I read about forge some time ago, but the problem is reading the private key from the browser.
You do not read or extract a private key. That is the point. The whole signing process is done on client (can happen even outside the operating system). You provide the hash, client answers with signature.
Sorry, but I cannot 100% understand what you are trying to do :(
We need two things:
The client signing process is following (parameters for to_pdf_file_b() are shown in code below):
Below is a simplified version of what should be implemented. Of course not in this form, it is just meta code to explain what I am trying to do. There are some certificate checks that should be changed (actually no pfx/p12 certs are needed in this case).
public function to_pdf_file_b($rebuild = false, $return_raw = false, $signature_contents= null) : Buffer {
....
if ($_signature !== null) {
// In case that the document is signed, calculate the signature
$_signature->set_sizes($_doc_to_xref->size(), $_doc_from_xref->size());
$_signature["Contents"] = new PDFValueSimple("");
$_signable_document = new Buffer($_doc_to_xref->get_raw() . $_signature->to_pdf_entry() . $_doc_from_xref->get_raw());
// new
if ($return_raw) {
return $_signable_document->get_raw();
}
// new
if (empty($signature_contents)) {
// We need to write the content to a temporary folder to use the pkcs7 signature mechanism
$temp_filename = tempnam(__TMP_FOLDER, 'pdfsign');
$temp_file = fopen($temp_filename, 'wb');
fwrite($temp_file, $_signable_document->get_raw());
fclose($temp_file);
// Calculate the signature and remove the temporary file
$certificate = $_signature->get_certificate();
$signature_contents = PDFUtilFnc::calculate_pkcs7_signature($temp_filename, $certificate['cert'], $certificate['pkey'], __TMP_FOLDER);
unlink($temp_filename);
}
// Then restore the contents field
$_signature["Contents"] = new PDFValueHexString($signature_contents);
// Add this object to the content previous to this document xref
$_doc_to_xref->data($_signature->to_pdf_entry());
}
// Reset the state to make signature objects not to mess with the user's objects
$this->pop_state();
return new Buffer($_doc_to_xref->get_raw() . $_doc_from_xref->get_raw());
}
...
Hi @malamalca
I have created a new branch signature_placeholder. In that version, functions to get the pdf file (i.e. to_pdf_file_s
, to_pdf_file_s
, and to_pdf_file_b
) accept a parameter calculate_signature_hash
that enables to calculate or not the hash using the certificates.
If setting calculate_signature_hash
to false, the signature hash will contain a placeholder (i.e. 0000000...000). Then you can calculate the hash using an external application and substitute it with your calculated value.
The reasoning is that the dates would change if you call the SAPP functions at different times, and therefore the document would change (thus changing the hash). I think that doing this differently will not add value but will add complexity by having to deal with the modification date and so on.
Could you please check if it is good for you?
__SIGNATURE_MAX_LENGTH
. Then you can compute the signature hash by substituting the <000...000>
by an empty value and then apply the algorithm to the resulting content. Later you can substitute the <000...000>
by the computed hash <***computed hash with a size of __SIGNATURE_MAX_LENGTH to keep the byte ranges***>
.The start is ok, it could be implemented as such. Manually replacing signature contents with PHP would work too.
But there is a major problem - the $_signature will not be generated because there are no certificates passed to SAPP when signing on client.
https://github.com/dealfonso/sapp/blob/1a2d70d6648c2ed5ca595011493d8e7ca116aa6a/src/PDFDoc.php#L692 https://github.com/dealfonso/sapp/blob/1a2d70d6648c2ed5ca595011493d8e7ca116aa6a/src/PDFDoc.php#L398
Hi,
you are right. I have updated the branch to reorganize the code so that now it is a little more didactic and it is easier to understand what is the structure of a PDF document.
And now, I have also included a new function to_pdf_with_signature_placeholder
that prepares the structure with a placeholder, to store the certificate. I have also included two new examples: pdfpreparesign.php
and pdfpreparesigni.php
to demonstrate how to use that function.
Could you please verify that the branch is working as expected?
hi @malamalca, did this worked for you?
Hi,
it would be great to have an ability to implement signing of pdfs on a client side.
Would it be possible with SAPP?