Mirian Okradze
Mirian Okradze

Reputation: 355

PDFNet Digital Signature in Node JS using Google KMS

I've seen example of signing https://www.pdftron.com/documentation/nodejs/guides/features/signature/sign-pdf

signOnNextSave uses PKCS #12 certificate, but I use Google KMS for asymmetric signing to keep private keys safe.

Here is example of signing and verifying by Google Cloud KMS

I tried to implement custom SignatureHandler but Node.JS API is different from Java or .NET https://www.pdftron.com/api/pdfnet-node/PDFNet.SignatureHandler.html

How can I implement custom signing and verifying logic?

const data = Buffer.from('pdf data')

// We have 2048 Bit RSA - PSS Padding - SHA256 Digest key in Google Cloud KMS
const signAsymmetric = async () => {
  const hash = crypto.createHash('sha256')
  hash.update(data)
  const digest = hash.digest()
  const digestCrc32c = crc32c.calculate(digest)

  // Sign the data with Cloud KMS
  const [signResponse] = await client.asymmetricSign({
    name: locationName,
    digest: {
      sha256: digest
    },
    digestCrc32c: {
      value: digestCrc32c
    }
  })

  if (signResponse.name !== locationName) {
    throw new Error('AsymmetricSign: request corrupted in-transit')
  }
  if (!signResponse.verifiedDigestCrc32c) {
    throw new Error('AsymmetricSign: request corrupted in-transit')
  }
  if (
    crc32c.calculate(signResponse.signature) !==
    Number(signResponse.signatureCrc32c.value)
  ) {
    throw new Error('AsymmetricSign: response corrupted in-transit')
  }

  // Returns signature which is buffer
  const encoded = signResponse.signature.toString('base64')
  console.log(`Signature: ${encoded}`)

  return signResponse.signature
}

// Verify data with public key
const verifyAsymmetricSignatureRsa = async () => {
  const signatureBuffer = await signAsymmetric()
  const publicKeyPem = await getPublicKey()

  const verify = crypto.createVerify('sha256')
  verify.update(data)
  verify.end()

  const key = {
    key: publicKeyPem,
    padding: crypto.constants.RSA_PKCS1_PSS_PADDING
  }

  // Verify the signature using the public key
  const verified = verify.verify(key, signatureBuffer)
  return verified
}

Upvotes: 0

Views: 515

Answers (1)

Shakthi Wijeratne
Shakthi Wijeratne

Reputation: 111

At this time, the PDFTron SDK only supports custom handlers on C++, Java, and C# (there are more plans to include additional languages in the future).

On a different platform like C++, you would extend the custom handler functions by putting hash.update(data) into SignatureHandler::AppendData, and the rest of signAsymmetric would go into SignatureHandler::CreateSignature. A name would be given to the custom handler for interoperability like Adobe.PPKLite (we do not yet support custom handler SubFilter entries, only Filter -- see PDF standard for the difference -- but this won't matter so long as you use a verification tool that supports Filter Adobe.PPKLite). Please see the following link for a concrete example: https://www.pdftron.com/documentation/samples/cpp/DigitalSignaturesTest

As for verification, our code can already do this for you if your signatures fulfill the following conditions:

  1. they use a standard digest algorithm
  2. they use RSA to sign
  3. they use the correct data formats according to the PDF standard (i.e. detached CMS, digital signature dictionary)

If you have more questions or require more details, please feel free to reach out to PDFTron support at [email protected]

Upvotes: 2

Related Questions