Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Digital signatures in pdf.js #1076

Open
soa-x opened this issue Jan 13, 2012 · 191 comments
Open

Digital signatures in pdf.js #1076

soa-x opened this issue Jan 13, 2012 · 191 comments

Comments

@soa-x
Copy link

@soa-x soa-x commented Jan 13, 2012

Hi! We are interested about when or if you´re going to implement the Signature Data View (Xades, Pades & Cades) in the PDF viewer (PDF.js)

Kind Regards

Alejandro Pinedo,
SOA-X

@brendandahl
Copy link
Contributor

@brendandahl brendandahl commented Jan 13, 2012

There are currently no imminent plans to implement this feature. We haven't seen it come up much so it hasn't been a priority. We're always looking for more contributors though, so we'd welcome any patches to add this feature. If you're interested in adding it feel free to stop by our IRC channel(#pdfjs irc.mozilla.org) if you have questions.

Brendan

@fermo111
Copy link

@fermo111 fermo111 commented Feb 28, 2014

Hi

what is the present state on the implementation of this feature?

Thanks

@yurydelendik
Copy link
Contributor

@yurydelendik yurydelendik commented Feb 28, 2014

@fermo111 Not implemented yet, but I will be glad to coach somebody who is willing to take this task.

@wolvz
Copy link

@wolvz wolvz commented Mar 31, 2014

@yurydelendik I'm interested in implementing the feature of presenting digital signatures of PDF files in pdf.js. How can I contact you?

@yurydelendik
Copy link
Contributor

@yurydelendik yurydelendik commented Mar 31, 2014

@wolvz please find me at IRC irc.mozilla.org channel #pdfjs (that's simplest) or join any of our public meetings to coordinate stuff.

@wolvz
Copy link

@wolvz wolvz commented May 31, 2014

I'm trying to implement SigWidgetAnnotation (like TextAnnotation, LinkAnnotation), in annotation.js, for supporting digital signatures in pdf.js.
The signature is showing up in the pdf viewer, and I already can extract and verify the certificates embbeded in the DER-encoded PKCS7 object...
Now I'm moving into the next step, which is to verify the message digest of the file.
For that I need to have access to the file contents... I dont' know if it's possible or not to have access to that from annotation.js, but I can't figure it out. The best I could do was to get the contents in core.js using:

var contentStreamPromise = this.pdfManager.ensure(this, 'getContentStream',[]);
var dataPromises = Promise.all([contentStreamPromise]);
dataPromises.then(function(data) {
var contentStream = data[0];
var contents = contentStream.str.bytes;
return contents;
});

Can someone please enlighten me on what is the best way to get file contents in annotation.js?
Thanks in advance...

@ashrafulkarim
Copy link

@ashrafulkarim ashrafulkarim commented Sep 9, 2014

wolvz,
any progress in this regard?

@brendandahl brendandahl modified the milestones: 2014 Q3, 2014 Q4 Oct 2, 2014
@brendandahl brendandahl modified the milestone: 2014 Q4 Jan 8, 2015
@corynewey
Copy link

@corynewey corynewey commented Jan 31, 2015

@yurydelendik @wolvz
I am extremely interested in the digital signature display feature. I cloned wolvz's repository and built the code but when I try to use it, I'm getting a promise rejection with this error: "require is not defined". Could anyone explain what would cause that error and how I could fix it? Also, I am very willing to continue the work on this feature. I've worked with pdf's in Java via the iText library but working with them in javascript is something I've never tried before. Could someone direct me to some documentation/tutorial that could get me pointed in the right direction so that I can figure out where to start as I try to move this feature further down the field?

@mrpandya007
Copy link

@mrpandya007 mrpandya007 commented Mar 18, 2015

I am confused. What i have to do in my pdf.js library to show digital signature pdf in pdfJS

@mrpandya007
Copy link

@mrpandya007 mrpandya007 commented Mar 18, 2015

untitled

This signature and certificate both showing in pdf.. but when i open it in pdf.js it wont showing there.

@wolvz
Copy link

@wolvz wolvz commented Mar 18, 2015

@mrpandya007, the digital signature doesn't show because the developers chose to hide it until they have signature verification feature working.
If I recall, if you want them simply to show up you have to comment lines 389 to 392 here: https://github.com/mozilla/pdf.js/blob/master/src/core/annotation.js#L389
Not sure though, and I can't test it right now.

@mrpandya007
Copy link

@mrpandya007 mrpandya007 commented Mar 18, 2015

@wolvz, Thanx for the response but its already commented. PLease look into this,, Crystal report's generated pdf signature is not showing but DevExpress generated pdf is showing it properly

@mrpandya007
Copy link

@mrpandya007 mrpandya007 commented Mar 25, 2015

Please answer me .... what i have to do.. I can give you that pdf to test

@timvandermeij
Copy link
Contributor

@timvandermeij timvandermeij commented Mar 25, 2015

There is no good support for digital signatures yet, so this will have to be implemented.

@mrpandya007
Copy link

@mrpandya007 mrpandya007 commented Mar 27, 2015

How many days it will take to fix this problem of digital signature because we are dependent on your lib.

@timvandermeij
Copy link
Contributor

@timvandermeij timvandermeij commented Mar 27, 2015

It might take a long time as this feature will have to be developed by someone and there are currently higher-priority issues.

@mrpandya007
Copy link

@mrpandya007 mrpandya007 commented Mar 30, 2015

heading

Why i am facing such issue of "=" sign in Headings, only in pdf.js, after downloading the file it gone.
any solution please. It is happens only in telerik generated pdf.

@lainosantos
Copy link

@lainosantos lainosantos commented Oct 22, 2020

@stephanrauh Thanks.

PDFViewerApplicationOptions.set('renderInteractiveForms', false);

Is there a way to enable forms and show signatures?

@stephanrauh
Copy link

@stephanrauh stephanrauh commented Oct 26, 2020

@lainosantos No, but I've found a nice walk-through how to build your own forms. The example assumes that renderInteractiveForms is dectivated. It uses Angular, but I guess you can extract the idea even if you're using a different framework: https://medium.com/factory-mind/angular-pdf-forms-fa72b15c3fbd

@Epsiom
Copy link

@Epsiom Epsiom commented Oct 26, 2020

I have more urgent matters for the moment and cannot spend time on the task, but if anyone manages to import an up-to-date pdf.js version on Angular 9, he would have my deepest thanks.

@Epsiom
Copy link

@Epsiom Epsiom commented Oct 26, 2020

@stephanrauh ...Well, except that I need to be compatible IE11 and only use the canvas directly to have a custom-made pdf viewer, so I cannot use that, sadly.
I cannot use ng2-pdf-viewer either, or anything of the sort, I am really asking about pdf.js in itself, which is a really niche case.

@QZhongyi
Copy link

@QZhongyi QZhongyi commented Dec 15, 2020

I've successfully show the signatures by commenting this.setFlags(AnnotationFlag.HIDDEN);, but it disappeared again after I zoom in the pdf by adjusting width of the parent element. Is there any solutions?

@lexcorp
Copy link

@lexcorp lexcorp commented Dec 31, 2020

If anyone is interested in biometric signatures:

https://github.com/DennisWacom/AlphaSign

AlphaSign_SignatureSDK

AlphaSign_SignedDocument

You can even use certificates...

@SkyGrass
Copy link

@SkyGrass SkyGrass commented Jan 6, 2021

@Epsiom Managed to get the signature to view. In pdf.worker.js add this on line 18480
case "Sig":
return new SquareAnnotation(parameters);
Is the switch just above this line.
(0, _util.warn)('Unimplemented widget field type "' + fieldType + '", ' + "falling back to base field type.");

That worked for me, you saved my day, thank you.

worked for me ! thank you.

@earthchie
Copy link

@earthchie earthchie commented Jan 15, 2021

Hi guys. I've been searching for a way to parsing signature information from PDF so at some point I came across this thread.
It's not related to PDF.js but this can be a workaround anyway. So I'm gonna share it.

Alright, if you happen to open signed-PDF with a text editor and search for a word adbe.pkcs7.detached you'll found this chunk of data.

image

there will be 5 lines of data for each signature attached to this document.

the first line and last line has nothing much, just ignore it.

on the 2nd line, data in between <</Contents <$HexDerIsHere> is a Der in hex format. You can convert it to ASN.1 then to Signature message with forge.js

you can also get a Location, Timestamp of signature, and Reason on the 3rd and 4th line.

My English is bad I think I talk too much, I should let the code speak.

Dependency: forge.js

<form id="getPDFSignature">
    <input type="file" name="pdf" accept="application/pdf" required>
    <button>get Signatures</button>
</form>
document.getElementById('getPDFSignature').onsubmit = function (e) {
    e.preventDefault();

    let FR = new FileReader();
    FR.onload = function (e) {
        let Signatures = getPDFSignature(e.target.result);
        if(Signatures){
            console.log(Signatures);
        }else{
            alert('This document does not contains any signature.');
        }
    }
    FR.readAsText(this.pdf.files[0]);

    return false;
}

function getPDFSignature(pdf){

    let Signatures = [];
    let PKCS7 = pdf.split(/\n\n/).filter(d=>d.indexOf('adbe.pkcs7.detached') > -1); // search for paragraph with word "adbe.pkcs7.detached"

    PKCS7.forEach(function(sig){
        let sigHex = sig.split(/\n/)[1].slice(13, -1).replace(/(?:00)*$/, ''); // get signature from the second line, also remove 0 padding at the end
        let p7Asn1 = forge.asn1.fromDer(hex2str(sigHex)); // convert hex to String to get Der, convert Der to ASN.1
        let message = forge.pkcs7.messageFromAsn1(p7Asn1); // convert ASN.1 to Signature Message

        let meta = sig.match(/\((.*?)\)/g); // [Location, Timestamp, Reason, ContactInfo]
        
        // timestamp format from string like this -> "(D:20210114234159+07'00')"
        let timestamp = `${meta[1].slice(3,7)}-${meta[1].slice(7,9)}-${meta[1].slice(9,11)}T${meta[1].slice(11,13)}:${meta[1].slice(13,15)}:${meta[1].slice(15,20)}${meta[1].slice(21,23)}`;
        
        meta = {
            Location: meta[0].slice(1,-1),
            M: timestamp,
            Reason: meta[2].slice(1,-1),
            ContactInfo: meta[3].slice(1,-1),
        };

        Signatures.push({
            message: message,
            meta: meta
        });
    })
}

function hex2str(str1){
	var hex  = str1.toString();
	var str = '';
	for (var n = 0; n < hex.length; n += 2) {
		str += String.fromCharCode(parseInt(hex.substr(n, 2), 16));
	}
	return str;
}
@softboy99
Copy link

@softboy99 softboy99 commented Feb 4, 2021

Hi,
we need this too

@Mageenz
Copy link

@Mageenz Mageenz commented Feb 6, 2021

@Epsiom Managed to get the signature to view. In pdf.worker.js add this on line 18480
case "Sig":
return new SquareAnnotation(parameters);
Is the switch just above this line.
(0, _util.warn)('Unimplemented widget field type "' + fieldType + '", ' + "falling back to base field type.");

That worked for me, you saved my day, thank you.

worked for me ! thank you.
nouse in v2.6.347

@stephanrauh
Copy link

@stephanrauh stephanrauh commented Feb 6, 2021

@earthchie Your code snippet looks promising. Does it also verify the signature is valid?
(I'm new to cryptography, so I really don't know).

@softboy99
Copy link

@softboy99 softboy99 commented Feb 7, 2021

Hi,
I'm confused. Does this lib have api to digitally sign the pdf file? or we discussed here is just to show the signed pdf's digital signature?

@stephanrauh
Copy link

@stephanrauh stephanrauh commented Feb 7, 2021

@softboy99 No, pdf.js doesn't have an API to sign a PDF file. And it doesn't display digital signatures because the team discovered it's difficult to verify the signature is valid. However, some people found out it's possible to display signatures nonetheless. What I'm interested in is the original idea: displaying valid, correctly signed signatures, and being able to detect fraud signatures. The code snippet provided by earthchie seems to point into this direction. But since I'm new to cryptography, I can't tell whether it can be used to verify the signature is valid. Does anybody following this discussion know?

@softboy99
Copy link

@softboy99 softboy99 commented Feb 8, 2021

Hi,
@stephanrauh, thanks for your clarifications, this issue has been opened almost 10 years. I suggests pdf.js should design this api because it is very important to many officialy published pdf files, otherwise, why the pdf is needed, they can use other file formats. We should use community power to do this. Suggest the following lib for refence:
https://github.com/Communication-Systems-Group/pdfsign.js
,which use forge lib for the cryptography.

@rmhrisk
Copy link

@rmhrisk rmhrisk commented Feb 8, 2021

@softboy99 No, pdf.js doesn't have an API to sign a PDF file. And it doesn't display digital signatures because the team discovered it's difficult to verify the signature is valid. However, some people found out it's possible to display signatures nonetheless. What I'm interested in is the original idea: displaying valid, correctly signed signatures, and being able to detect fraud signatures. The code snippet provided by earthchie seems to point into this direction. But since I'm new to cryptography, I can't tell whether it can be used to verify the signature is valid. Does anybody following this discussion know?

We do both sign and verify with https://verify.ink

@softboy99
Copy link

@softboy99 softboy99 commented Feb 8, 2021

Hi,
@rmhrisk, it is a cloud server side solution. Ther're many colud server side solution in the world. we discussed here is an client side solution.

@rmhrisk
Copy link

@rmhrisk rmhrisk commented Feb 8, 2021

Hi,
@rmhrisk, it is a cloud server side solution. Ther're many colud server side solution in the world. we discussed here is an client side solution.

No, The document doesn’t leave the browser, the validation happens in browser, the signing happens in the browser, the encryption/decryption happens on the browser, the rendering happens in the browser, it’s all client side.

@softboy99
Copy link

@softboy99 softboy99 commented Feb 8, 2021

Hi,
@rmhrisk, it is a cloud server side solution. Ther're many colud server side solution in the world. we discussed here is an client side solution.

No, The document doesn’t leave the browser, the validation happens in browser, the rendering happens in the browser, it’s all client side.

If your computer cannot connect to https://verify.ink/viewer, what will happen?

src="https://verify.ink/viewer?url={YOUR_DOCUMENT_URL}"

@rmhrisk
Copy link

@rmhrisk rmhrisk commented Feb 8, 2021

Hi,
@rmhrisk, it is a cloud server side solution. Ther're many colud server side solution in the world. we discussed here is an client side solution.

No, The document doesn’t leave the browser, the validation happens in browser, the rendering happens in the browser, it’s all client side.

If your computer cannot connect to https://verify.ink/viewer, what will happen?

src="https://verify.ink/viewer?url={YOUR_DOCUMENT_URL}"

It’s possible to host the web component on ones own servers too.

@stephanrauh
Copy link

@stephanrauh stephanrauh commented Feb 8, 2021

@softboy99 I'm not a member of the pdf.js team. I just maintain of fork of pdf.js for my own PDF viewer. However, what we can do is implement the feature in ngx-extended-pdf-viewer until it's mature. After that, we can offer the implementation to pdf.js. I can't do that alone (for lack of knowledge and lack of leisure time), so I'd appreciate help. Maybe even your help?

@earthchie
Copy link

@earthchie earthchie commented Feb 18, 2021

@earthchie Your code snippet looks promising. Does it also verify the signature is valid?
(I'm new to cryptography, so I really don't know).

Sorry for the late reply.

The answer is no.
However, this might help you: https://github.com/MohammedEssehemy/node-sign-validate-pdf/blob/master/script.js#L338

If I understand correctly. There are two steps to verify a PDF signature.

  1. decrypt the signature message with a public key of the singer. you'll get the hash as a result.
  2. sha256 the PDF content, then compare with step 1. if two hashes match, the signature is valid.

but it is not as easy as it seems. In step 2, you'll need to slice some of the PDF content precisely, or else the hash will shift.
The start and end positions can be found in ByteRange on the 4th lines. This is very tricky and I still can't figure what I do wrong because I can't get the right hash yet.

Recently I also found a signed-PDF which signature is not in the 5-line format too. So the snippet I provided earlier might not work all the time.

Please try this instead. (I know, the code is a mess lol. Please forgive me.)

<form id="getPDFSignature">
    <input type="file" name="pdf" accept="application/pdf" required>
    <button>get Signatures</button>
</form>
document.getElementById('getPDFSignature').onsubmit = function (e) {
    e.preventDefault();

    let FR = new FileReader();
    FR.onload = function (e) {
        let Signatures = getPDFSignature(e.target.result);
        if(Signatures){
            console.log(Signatures);
        }else{
            alert('This document does not contains any signature.');
        }
    }
    FR.readAsText(this.pdf.files[0]);

    return false;
}

function getPDFSignature(pdf){
  return pdf.split(/endobj/).filter(l=>l.indexOf('adbe.pkcs7.detached')>-1).map(d=>{
      let sig = {};
      d = d.trim();
      let date = d.match(/\/M\(D:(.*?)\)/)[1].replace("'",'').match(/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(.{5})/);
      let reason = d.match(/\/Reason\((.*?)\)\//);
      let location = d.match(/\/Location\((.*?)\)\//);
      sig.raw = d;
      sig.header = d.match(/(\d) (\d) obj/)[0];
      sig.ByteRange = d.match(/\/ByteRange.*?\[(.*?)\]/)[1].trim().split(' ').map(i=>+i);
      sig.Date = new Date(`${date[1]}-${date[2]}-${date[3]}T${date[4]}:${date[5]}:${date[6]}${date[7]}`);
      sig.Contents = d.match(/\/Contents *?\<(.*?)\>/)[1].replace(/(?:00)*$/, '');
      sig.Signature = {Der: hex2str(sig.Contents)};
      sig.Signature.ASN1 = forge.asn1.fromDer(sig.Signature.Der);
      sig.Signature.message = forge.pkcs7.messageFromAsn1(sig.Signature.ASN1);
  
      if(reason){
          sig.Reason = reason[1];
      }else{
          sig.Reason = '';
      }
      if(location){
          sig.Location = location[1];
      }else{
          sig.Location = '';
      }
      
      return sig;
  });
}

function hex2str(str1){
	var hex  = str1.toString();
	var str = '';
	for (var n = 0; n < hex.length; n += 2) {
		str += String.fromCharCode(parseInt(hex.substr(n, 2), 16));
	}
	return str;
}

Will update ya later once I successfully validate the signature with PDF content.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet