OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

Embed digital signature(pkcs7) to pdf

  • Thread starter Thread starter Deepak Gupta
  • Start date Start date
D

Deepak Gupta

Guest
I am implementing signing of a PDF. I have pkcs7 value and I want to embed it in the PDF.

I am using pdf-lib and node-signpdf

The PDF file is getting signed, but when verifying using pdfsign, I am getting this error:

Code:
pdfsig signed.pdf
Digital Signature Info of: signed.pdf
Syntax Error (0): Illegal values in ByteRange array
Signature #1:
  - Signer Certificate Common Name: (null)
  - Signer full Distinguished Name: (null)
  - Signing Time: Jun 24 2024 19:49:21
  - Signing Hash Algorithm: unknown
  - Signature Type: adbe.pkcs7.detached
  - Signed Ranges: [0 - 99393], [99403 - 116849]
  - Not total document signed
  - Signature Validation: Signature has not yet been verified.

This is my code:

Code:
const fs = require('fs');
const { PDFDocument, PDFName, PDFHexString, PDFArray, PDFDict, PDFNumber } = require('pdf-lib');
const { plainAddPlaceholder } = require('node-signpdf/dist/helpers');

async function embedSignatureToPdf(pdfPath, outputPdfPath, base64Signature) {
    try {
        // Read the PDF
        const pdfBuffer = fs.readFileSync(pdfPath);

        // Add a placeholder for the signature
        const pdfWithPlaceholder = plainAddPlaceholder({
            pdfBuffer,
            reason: 'I am the author',
            contactInfo: '[email protected]',
            name: 'Author',
            location: 'Location',
        });

        // Debugging: Log the length of the PDF with placeholder
        console.log('pdfWithPlaceholder length:', pdfWithPlaceholder.length);

        // Convert Base64 signature to Buffer
        const pkcs7Buffer = Buffer.from(base64Signature, 'base64');

        // Find the ByteRange placeholder position
        const byteRangePlaceholder = '**********';
        const byteRangePos = pdfWithPlaceholder.indexOf(byteRangePlaceholder);
        if (byteRangePos === -1) {
            throw new Error('Could not find ByteRange placeholder in the PDF');
        }

        // Calculate the lengths of the first and second ranges
        const length1 = byteRangePos;
        const length2 = pdfWithPlaceholder.length - (length1 + byteRangePlaceholder.length);

        // Calculate ByteRange values
        const byteRange = [
            0, // start1
            length1, // length1
            length1 + byteRangePlaceholder.length, // start2
            length2, // length2
        ];

        // Ensure the ByteRange values are correct
        console.log('ByteRange:', byteRange);
        const totalSignedLength = length1 + length2;
        console.log('totalSignedLength:', totalSignedLength);
        if (totalSignedLength !== pdfWithPlaceholder.length - byteRangePlaceholder.length) {
            throw new Error('ByteRange values do not sum up to the total document length minus the placeholder length');
        }

        // Format ByteRange values as a string
        const byteRangeStr = byteRange.map(val => `0000000000${val}`.slice(-10)).join(' ');

        // Debugging: Log ByteRange string
        console.log('ByteRangeStr:', byteRangeStr);

        // Replace ByteRange placeholder with actual values
        let pdfWithByteRange = Buffer.concat([
            pdfWithPlaceholder.slice(0, byteRangePos),
            Buffer.from(byteRangeStr),
            pdfWithPlaceholder.slice(byteRangePos + byteRangePlaceholder.length),
        ]);

        // Load the PDF document with ByteRange replaced
        const signedPdfDoc = await PDFDocument.load(pdfWithByteRange);

        // Get the AcroForm dictionary
        const acroForm = signedPdfDoc.context.lookup(signedPdfDoc.catalog.get(PDFName.of('AcroForm')));
        if (!acroForm) {
            throw new Error('Could not find AcroForm in the PDF');
        }

        // Get the signature field
        const fields = acroForm.lookup(PDFName.of('Fields'), PDFArray);
        const signatureField = fields.lookup(0, PDFDict);
        const signatureDict = signatureField.lookup(PDFName.of('V'), PDFDict);

        // Set the /ByteRange entry with the calculated ByteRange
        const byteRangeArray = PDFArray.withContext(signedPdfDoc.context);
        byteRange.forEach(val => byteRangeArray.push(PDFNumber.of(val)));
        signatureDict.set(PDFName.of('ByteRange'), byteRangeArray);

        // Set the /Contents entry with the PKCS#7 signature
        const hexSignature = PDFHexString.of(pkcs7Buffer.toString('hex'));

        // Ensure the contents fit in the allocated space
        const placeholderLengthBytes = byteRangePlaceholder.length * 2; // Each byte is represented by 2 hex digits
        const paddedSignature = hexSignature.value.padEnd(placeholderLengthBytes, '0');

        signatureDict.set(PDFName.of('Contents'), PDFHexString.of(paddedSignature));

        // Save the signed PDF
        const signedPdfBytes = await signedPdfDoc.save();
        fs.writeFileSync(outputPdfPath, signedPdfBytes);

        console.log('PDF signed successfully!');
    } catch (error) {
        console.error('Error signing PDF:', error);
    }
}

<p>I am implementing signing of a PDF. I have pkcs7 value and I want to embed it in the PDF.</p>
<p>I am using pdf-lib and node-signpdf</p>
<p>The PDF file is getting signed, but when verifying using pdfsign, I am getting this error:</p>
<pre><code>pdfsig signed.pdf
Digital Signature Info of: signed.pdf
Syntax Error (0): Illegal values in ByteRange array
Signature #1:
- Signer Certificate Common Name: (null)
- Signer full Distinguished Name: (null)
- Signing Time: Jun 24 2024 19:49:21
- Signing Hash Algorithm: unknown
- Signature Type: adbe.pkcs7.detached
- Signed Ranges: [0 - 99393], [99403 - 116849]
- Not total document signed
- Signature Validation: Signature has not yet been verified.
</code></pre>
<p>This is my code:</p>
<pre><code>const fs = require('fs');
const { PDFDocument, PDFName, PDFHexString, PDFArray, PDFDict, PDFNumber } = require('pdf-lib');
const { plainAddPlaceholder } = require('node-signpdf/dist/helpers');

async function embedSignatureToPdf(pdfPath, outputPdfPath, base64Signature) {
try {
// Read the PDF
const pdfBuffer = fs.readFileSync(pdfPath);

// Add a placeholder for the signature
const pdfWithPlaceholder = plainAddPlaceholder({
pdfBuffer,
reason: 'I am the author',
contactInfo: '[email protected]',
name: 'Author',
location: 'Location',
});

// Debugging: Log the length of the PDF with placeholder
console.log('pdfWithPlaceholder length:', pdfWithPlaceholder.length);

// Convert Base64 signature to Buffer
const pkcs7Buffer = Buffer.from(base64Signature, 'base64');

// Find the ByteRange placeholder position
const byteRangePlaceholder = '**********';
const byteRangePos = pdfWithPlaceholder.indexOf(byteRangePlaceholder);
if (byteRangePos === -1) {
throw new Error('Could not find ByteRange placeholder in the PDF');
}

// Calculate the lengths of the first and second ranges
const length1 = byteRangePos;
const length2 = pdfWithPlaceholder.length - (length1 + byteRangePlaceholder.length);

// Calculate ByteRange values
const byteRange = [
0, // start1
length1, // length1
length1 + byteRangePlaceholder.length, // start2
length2, // length2
];

// Ensure the ByteRange values are correct
console.log('ByteRange:', byteRange);
const totalSignedLength = length1 + length2;
console.log('totalSignedLength:', totalSignedLength);
if (totalSignedLength !== pdfWithPlaceholder.length - byteRangePlaceholder.length) {
throw new Error('ByteRange values do not sum up to the total document length minus the placeholder length');
}

// Format ByteRange values as a string
const byteRangeStr = byteRange.map(val => `0000000000${val}`.slice(-10)).join(' ');

// Debugging: Log ByteRange string
console.log('ByteRangeStr:', byteRangeStr);

// Replace ByteRange placeholder with actual values
let pdfWithByteRange = Buffer.concat([
pdfWithPlaceholder.slice(0, byteRangePos),
Buffer.from(byteRangeStr),
pdfWithPlaceholder.slice(byteRangePos + byteRangePlaceholder.length),
]);

// Load the PDF document with ByteRange replaced
const signedPdfDoc = await PDFDocument.load(pdfWithByteRange);

// Get the AcroForm dictionary
const acroForm = signedPdfDoc.context.lookup(signedPdfDoc.catalog.get(PDFName.of('AcroForm')));
if (!acroForm) {
throw new Error('Could not find AcroForm in the PDF');
}

// Get the signature field
const fields = acroForm.lookup(PDFName.of('Fields'), PDFArray);
const signatureField = fields.lookup(0, PDFDict);
const signatureDict = signatureField.lookup(PDFName.of('V'), PDFDict);

// Set the /ByteRange entry with the calculated ByteRange
const byteRangeArray = PDFArray.withContext(signedPdfDoc.context);
byteRange.forEach(val => byteRangeArray.push(PDFNumber.of(val)));
signatureDict.set(PDFName.of('ByteRange'), byteRangeArray);

// Set the /Contents entry with the PKCS#7 signature
const hexSignature = PDFHexString.of(pkcs7Buffer.toString('hex'));

// Ensure the contents fit in the allocated space
const placeholderLengthBytes = byteRangePlaceholder.length * 2; // Each byte is represented by 2 hex digits
const paddedSignature = hexSignature.value.padEnd(placeholderLengthBytes, '0');

signatureDict.set(PDFName.of('Contents'), PDFHexString.of(paddedSignature));

// Save the signed PDF
const signedPdfBytes = await signedPdfDoc.save();
fs.writeFileSync(outputPdfPath, signedPdfBytes);

console.log('PDF signed successfully!');
} catch (error) {
console.error('Error signing PDF:', error);
}
}
</code></pre>
 
Top