vbuch / node-signpdf

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

Issues with signing pdf file with certificate from azure certificate vault with non-exportable private key #272

Open arvydas-kezunas opened 1 month ago

arvydas-kezunas commented 1 month ago

Greetings everyone, i am facing some issues with putting digital signatures on pdf files with using azure certificate vault. Problem appears when certificate is with non-exportable private key and have to rely on azure cryptography client. this is my current implementation:

   async signDocument(fileBuffer: Buffer, certName: string) {
    try {
      Logger.log(`Starting document signing process for certificate: ${certName}...`);

      Logger.log(`Retrieving certificate: ${certName} from Azure...`);
      const certificateData = await this.certificateClient.getCertificate(certName);

      Logger.log('Extracting Key ID from the certificate...');
      const keyId = certificateData.keyId;
      if (!keyId) {
        Logger.error('Key ID not found in the certificate.');
        throw new Error('Key ID not found for certificate');
      }
      Logger.log(`Key ID found: ${keyId}`);

      Logger.log(`Creating CryptographyClient with Key ID: ${keyId}...`);
      const cryptoClient = new CryptographyClient(keyId, this.credential);
      Logger.log('CryptographyClient created successfully.');

      Logger.log('Loading and modifying PDF document...');
      const pdfDoc = await PDFDocument.load(fileBuffer);
      pdflibAddPlaceholder({
        pdfDoc: pdfDoc,
        reason: 'I am the author of this document',
        location: 'Lithuania',
        contactInfo: 'namelastname@email.com',
        name: 'Name Lastname',
        widgetRect: [50, 100, 250, 150],
      });

      const pdfWithPlaceholderBytes = await pdfDoc.save();

      const documentHash = this.createHashWith(Buffer.from(pdfWithPlaceholderBytes));

      const signResult: SignResult = await cryptoClient.sign("RS256", documentHash);

      const azureSigner = new AzureVaultSigner(signResult.result);
      const signedPdfBytes = await SignPdf.sign(pdfWithPlaceholderBytes, azureSigner);

      Logger.log('Signature injected into PDF document successfully.');

      fs.writeFileSync('output-signed.pdf', signedPdfBytes);
      return signedPdfBytes;

    } catch (error) {
      Logger.error('Error signing document:', error.message);
      throw new Error(`Error signing document: ${error.message}`);
    }
  }  

    private createHashWith(buffer: Buffer): Buffer {
    const hash = createHash('sha256');
    hash.update(buffer);
    return hash.digest();
  }
import {Signer} from '@signpdf/signpdf'

class AzureVaultSigner extends Signer {
  signature: Buffer;
  constructor(signature: any) {
    super();
    this.signature = Buffer.from(signature);; // Store the signature
  }

  async sign(pdfBuffer, signingTime) {
    return pdfBuffer;
  }
}

export default AzureVaultSigner;

as i understand, Azures cryptoclient sign returns the signature it self, that later has to be injected in to original pdf. And i believe that issue is in my custom signer. and after running the api im getting this image

dhensby commented 1 month ago
import {Signer} from '@signpdf/signpdf'

class AzureVaultSigner extends Signer {
  signature: Buffer;
  constructor(signature: any) {
    super();
    this.signature = Buffer.from(signature);; // Store the signature
  }

  async sign(pdfBuffer, signingTime) {
    return pdfBuffer;
  }
}

export default AzureVaultSigner;

You're just returning the PDF in your signer and not the signature. If you change that, it may work

arvydas-kezunas commented 1 month ago

i will check that

arvydas-kezunas commented 1 month ago
import {Signer} from '@signpdf/signpdf'

class AzureVaultSigner extends Signer {
  signature: Buffer;
  constructor(signature: any) {
    super();
    this.signature = Buffer.from(signature);; // Store the signature
  }

  async sign(pdfBuffer, signingTime) {
    return pdfBuffer;
  }
}

export default AzureVaultSigner;

You're just returning the PDF in your signer and not the signature. If you change that, it may work

Maybe you have idea where i could fine example of custom signer that would work with my issue?