vbuch / node-signpdf

Simple signing of PDFs in node.
MIT License
723 stars 178 forks source link

Multiple signatures invalidates previous signatures #47

Closed vemundeldegard closed 4 years ago

vemundeldegard commented 4 years ago

Hi!

Thanks for creating this lib.

I am having trouble with adding multiple signatures by using plainAddPlaceholder(). If I add multiple signatures, all previous signatures get invalidated. I have attached the two PDFs.

Here is my code:

         import signer from './node-signpdf/signpdf';
         import plainAddPlaceholder from './node-signpdf/helpers/plainAddPlaceholder';

        // Create and get .p12 certificate
        const certificate = await createCertificate()

        // Add signature and forms
        pdfBuffer = await plainAddPlaceholder({
            pdfBuffer,
            reason: 'Because I can',
            signatureLength: certificate.length
        })

        // Sign document
        const file = signer.sign(
            pdfBuffer,
            certificate,
            {passphrase: 'password'}
        );

The createCertificate function creates a self-signed certificate:

import { pki, pkcs12, util, asn1 } from "node-forge"
import moment from "moment";

export default async () => {

    // generate a keypair
    let keys = pki.rsa.generateKeyPair(2048);

    // create a new certificate
    let cert = pki.createCertificate();

    // fill the required fields
    cert.publicKey = keys.publicKey;
    cert.serialNumber = '01';
    cert.validity.notBefore = moment().startOf('day').toDate();
    cert.validity.notAfter = moment().startOf('day').toDate();
    cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 3);  

    // Set issuer
    const issuer = [{
        name: 'commonName',
        value: 'salire.no'
    }, {
        name: 'countryName',
        value: 'NO'
    }, {
        shortName: 'ST',
        value: 'Vestland'
    }, {
        name: 'localityName',
        value: 'Bergen'
    }, {
        name: 'organizationName',
        value: 'Salire AS'
    }, 
    {
        shortName: 'OU',
        value: 'Salire'
    }];

    // Set subject
    const subject = [{
        name: 'commonName',
        value: 'My name'
    }, {
        name: 'countryName',
        value: 'NO'
    }, {
        shortName: 'ST',
        value: 'Vestland'
    }, {
        name: 'localityName',
        value: 'Bergen'
    }, {
        name: 'organizationName',
        value: 'Min organisasjon'
    }, {
        shortName: 'OU',
        value: ' '
    }];

    // here we set subject and issuer as different objects
    cert.setSubject(subject);
    cert.setIssuer(issuer);

    // the actual certificate signing
    cert.sign(keys.privateKey);

    // generate a p12 using AES (default)
    var newPkcs12Asn1 = pkcs12.toPkcs12Asn1(keys.privateKey, cert, 'password');

    // base64-encode p12
    const p12Der = asn1.toDer(newPkcs12Asn1).getBytes();
    var buffer = Buffer.from(p12Der, 'binary');

    return buffer
}

5e011ae8f6d4d2656fa8c4cc.pdf 5e011ae8f6d4d2656fa8c4cc (1).pdf

vbuch commented 4 years ago

Sorry for not responding earlier. Actually I just saw the issue for the first time now. You have reported the issue perfectly. I see there is the problem that #57 fixes in the first PDF. Then it just goes on with the second one. You have /Annots [ 13 0 R /MediaBox 0 0 595 842 31 0 R] So the /Annots is broken even in the first doc. The just released 1.2.2 fixes that. Sorry again for the delay @vemundeldegard

vbuch commented 4 years ago

1.2.3 also relates to /Annots. Hope all is well here.