Digital sign with Aws KMS

Hello

I want to sign documents using Aws KMS, but couldn’t find anything related to that on the documents.

Is it feasible?

Thank you

We are just releasing a new version of our SDK which will make this task easier.

Could you let us know what language+framework you are using so that we can provide you an answer.

1 Like

Thank you for the response.

Good to hear that you’re going to make it easier.

We’re using the Javascript SDK and wanted to implement the signing/verifying functionality in the backend with Python(Django) and Aws KSM.

Do you know any existing tools/ways/solutions for that? any help will be appreciated

Thanks again

Try the following Python code, but replace usage of SignDigest with your own code that contacts Amazon.

doc = PDFDoc(in_docpath)
doc.InitSecurityHandler()
page1 = doc.GetPage(1)

certification_sig_field = doc.CreateDigitalSignatureField(in_cert_field_name)
widgetAnnot = SignatureWidget.Create(doc, Rect(143, 287, 219, 306), certification_sig_field)
page1.AnnotPushBack(widgetAnnot)

# (OPTIONAL) Add an appearance to the signature field.
img = Image.Create(doc.GetSDFDoc(), in_appearance_image_path)
widgetAnnot.CreateSignatureAppearance(img)

##### The following section of sample code inside this function is mostly new and pertains to the custom signing APIs.

# Create a digital signature dictionary inside the digital signature field, in preparation for signing.
certification_sig_field.CreateSigDictForCustomCertification("Adobe.PPKLite",
    DigitalSignatureField.e_ETSI_CAdES_detached if in_PAdES_signing_mode is True else DigitalSignatureField.e_adbe_pkcs7_detached,
    7500) # For security reasons, set the contents size to a value greater than but as close as possible to the size you expect your final signature to be.
# ... or, if you want to apply a normal non-certification signature, use CreateSigDictForSigning instead.

# (OPTIONAL) Add more information to the signature dictionary.
certification_sig_field.SetLocation("Vancouver, BC")
certification_sig_field.SetReason("Document certification.")
certification_sig_field.SetContactInfo("www.pdftron.com")

# Set the signing time in the signature dictionary, if no secure embedded timestamping support is available from your signing provider.
current_date = Date()
current_date.SetCurrentTime()
certification_sig_field.SetSigDictTimeOfSigning(current_date)

doc.Save(in_outpath, SDFDoc.e_incremental)

# Digest the relevant bytes of the document in accordance with ByteRanges surrounding the signature.
digest = certification_sig_field.CalculateDigest(in_digest_algorithm_type)

# At this point, you can do your custom signing.
#out_signature = DigitalSignatureField.SignDigest(digest, in_private_key_file_path, in_keyfile_password, True, in_digest_algorithm_type)

# With buffer overload
out_signature = []
private_key_buf = []
private_key_file = MappedFile(in_private_key_file_path)
private_key_file_sz = private_key_file.FileSize()
private_key_file_reader = FilterReader(private_key_file)
private_key_buf = private_key_file_reader.Read(private_key_file_sz)
out_signature = DigitalSignatureField.SignDigest(digest, private_key_buf, in_keyfile_password, True, in_digest_algorithm_type)

# Write the signature to the document.
doc.SaveCustomSignature(out_signature, certification_sig_field, in_outpath)
1 Like

Thank you so much

When I tried to run the code, I encountered this error

Traceback (most recent call last):
  File "main.py", line 23, in <module>
    certification_sig_field.CreateSigDictForCustomCertification("Adobe.PPKLite",
  File "/home/mir/pdftron/.venv/lib/python3.8/site-packages/PDFNetPython3/PDFNetPython.py", line 5643, in <lambda>
    __getattr__ = lambda self, name: _swig_getattr(self, DigitalSignatureField, name)
  File "/home/mir/pdftron/.venv/lib/python3.8/site-packages/PDFNetPython3/PDFNetPython.py", line 80, in _swig_getattr
    raise AttributeError("'%s' object has no attribute '%s'" % (class_type.__name__, name))
AttributeError: 'DigitalSignatureField' object has no attribute 'CreateSigDictForCustomCertification'

also I couldn’t find “CreateSigDictForCustomCertification” in the pip package of yours

We just released a new SDK update, 9.1, which is now available on Pypl.

Please update to PDFNet 9.1 and try again.

1 Like

Thank you so much for the reply.

I’ve updated the library and sign a document however when I open it in Adobe Acrobat the signature is still invalid.

I created an RSA_2048 key in KMS for signing/verifying.

As I see in the KMS panel, these algorithms are valid for signing using this key

    RSASSA_PKCS1_V1_5_SHA_256
    RSASSA_PKCS1_V1_5_SHA_384
    RSASSA_PKCS1_V1_5_SHA_512
    RSASSA_PSS_SHA_256
    RSASSA_PSS_SHA_384
    RSASSA_PSS_SHA_512 

This is the code

import os
import hashlib
import boto3
from PDFNetPython3 import *


class AwsConfig:
    SIGN_AWS_ACCESS_KEY_ID = os.getenv('SIGN_AWS_ACCESS_KEY_ID') or 'AKIATMRHGXXX'
    SIGN_AWS_SECRET_ACCESS_KEY = os.getenv('SIGN_AWS_SECRET_ACCESS_KEY') or 'BXVTnahV9uUAbVloW4sAaZXXX'
    SIGN_AWS_REGION = os.getenv('SIGN_AWS_REGION') or 'us-east-2'
    SIGN_AWS_KEY_ID = os.getenv('SIGN_AWS_KEY_ID') or 'a3b2d70e-3a11-4ebe-81aXXX'


def sign(data):
    doc_hash = hashlib.sha256(data).digest()

    client = boto3.client(
        'kms',
        region_name=AwsConfig.SIGN_AWS_REGION,
        aws_access_key_id=AwsConfig.SIGN_AWS_ACCESS_KEY_ID,
        aws_secret_access_key=AwsConfig.SIGN_AWS_SECRET_ACCESS_KEY,
    )

    response = client.sign(
        KeyId=AwsConfig.SIGN_AWS_KEY_ID,
        Message=doc_hash,
        MessageType='DIGEST',
        SigningAlgorithm='RSASSA_PKCS1_V1_5_SHA_256'
    )
    client.verify
    return response['Signature']


PDFNet.Initialize("demo:1630101464969:78e7336503000000005495bc43021d4ea87b753b81f38676dXXX")


in_docpath = 'test.pdf'
in_cert_field_name = 'PDFTronCertificationSig'
in_PAdES_signing_mode = False
in_outpath = 'test_signed.pdf'
in_digest_algorithm_type = 1


doc = PDFDoc(in_docpath)
doc.InitSecurityHandler()
page1 = doc.GetPage(1)

certification_sig_field = doc.CreateDigitalSignatureField(in_cert_field_name)
widgetAnnot = SignatureWidget.Create(doc, Rect(143, 287, 219, 306), certification_sig_field)
page1.AnnotPushBack(widgetAnnot)

certification_sig_field.CreateSigDictForCustomCertification("Adobe.PPKLite", DigitalSignatureField.e_ETSI_CAdES_detached if in_PAdES_signing_mode is True else DigitalSignatureField.e_adbe_pkcs7_detached, 7500) 

certification_sig_field.SetLocation("Vancouver, BC")
certification_sig_field.SetReason("Document certification.")
certification_sig_field.SetContactInfo("www.pdftron.com")

current_date = Date()
current_date.SetCurrentTime()
certification_sig_field.SetSigDictTimeOfSigning(current_date)

doc.Save(in_outpath, SDFDoc.e_incremental)

digest = certification_sig_field.CalculateDigest(in_digest_algorithm_type)
out_signature = sign(open(in_outpath, 'rb').read())

doc.SaveCustomSignature(out_signature, certification_sig_field, in_outpath)

Do you have any clue what might be the problem?

Thanks again

Thank you for the update.

First, it appears you are digesting twice by mistake. Instead of

out_signature = sign(open(in_outpath, 'rb').read())

call just

out_signature = sign(digest)

Next, you should probably include your certificates in the CMS signature. As an example, in OpenSSL this is done by calling PKCS7_add_certificate.

If you are trying to create a PAdES signature then you also need to add ESS_Signing_Cert[V2]. The easiest way to sign would probably be to find an Amazon API for creating detached CMS signatures, and furnish it with the digest, certificates, and anything else you want to include as an attribute.

Good catch, thanks

For the second part, how do I add the certificate to the signature field? is there any API for that?

Thanks again

There is no API with us to store certificates manually. It is possible that Amazon will do so by default, however it is also possible that they will only include the signer certificate by default but not the root or intermediate(s). In case Amazon does not add them, you should first try to figure out if Amazon has an API/setting to enable certificate embedding into CMS signatures.

Otherwise, you can use OpenSSL to add certificates to the signature (which should be possible, since the certificates field is its own member of CMS according to RFC 5652, and not part of the signed ‘contents’ since it’s not the same as ‘signed attributes’).

It is possible that we may decide to add an API in future release to allow certificate addition to custom signatures. Also, we may add support in future for LTV-style certificate addition. We consider all customer feedback when deciding on new features.

Can you try the aforementioned ideas for the time being?

It is possible now to customize which certificates are added as part of signing, by usage of the custom signing API.

See the usage of the chain_certs argument to GenerateCMSSignature, within our new custom signing guide below.