Product: PDFTron Python
Product Version: 9.3.0
Please give a brief summary of your issue:
Having issues implementing Custom Digital Signatures with AWS HSM offering
Please describe your issue and provide steps to reproduce it:
I am attempting to follow the Custom Signing guide here and the signing in python guide here but I am unable to get a valid certified document after trying numerous different variations of the following code:
from PDFNetPython3 import *
from request_signature import request_signature
import os
license = os.getenv('PDFTRON_LICENSE')
PDFNet.Initialize(license)
in_docpath = 'test.pdf'
in_outpath = 'test output.pdf'
in_cert_path = 'aws_hsm/customerCA.crt'
in_sig_field_name = 'CertFieldName'
chain_cert_paths = ['aws_hsm/manufacturer_chain.crt', 'aws_hsm/aws_chain.crt']
in_PAdES_signing_mode = False
doc = PDFDoc(in_docpath)
page1 = doc.GetPage(1)
digsig_field = doc.CreateDigitalSignatureField(in_sig_field_name)
widgetAnnot = SignatureWidget.Create(doc, Rect(143, 287, 219, 306), digsig_field)
page1.AnnotPushBack(widgetAnnot)
digsig_field.CreateSigDictForCustomCertification("Adobe.PPKLite",\
DigitalSignatureField.e_ETSI_CAdES_detached if in_PAdES_signing_mode else DigitalSignatureField.e_adbe_pkcs7_detached,\
7500)
current_date = Date()
current_date.SetCurrentTime()
digsig_field.SetSigDictTimeOfSigning(current_date)
doc.Save(in_outpath, SDFDoc.e_incremental)
pdf_digest = digsig_field.CalculateDigest(DigestAlgorithm.e_SHA256)
signer_cert = X509Certificate(in_cert_path)
signedAttrs = DigitalSignatureField.GenerateCMSSignedAttributes(pdf_digest)
signedAttrs_digest = DigestAlgorithm.CalculateDigest(DigestAlgorithm.e_SHA256, signedAttrs)
signature_value = request_signature(list(signedAttrs_digest))
chain_certs = []
chain_certs.append(X509Certificate(chain_cert_paths[0])) #manufacturer_chain.crt
chain_certs.append(X509Certificate(chain_cert_paths[1])) #AWS_chain.crt
digest_algorithm_oid = ObjectIdentifier(ObjectIdentifier.e_SHA256)
signature_algorithm_oid = ObjectIdentifier(ObjectIdentifier.e_RSA_encryption_PKCS1)
cms_signature = DigitalSignatureField.GenerateCMSSignature(signer_cert, chain_certs, digest_algorithm_oid, signature_algorithm_oid, signature_value, signedAttrs)
in_opts = VerificationOptions(0)
verification_results = digsig_field.Verify(in_opts)
print(verification_results.GetDigestStatusAsString())
print(verification_results.GetDocumentStatusAsString())
doc.SaveCustomSignature(cms_signature, digsig_field, in_outpath)
And the request_signature code:
"""CloudHSM Demo"""
import os
import base64
import PyKCS11
from PyKCS11.LowLevel import CKF_RW_SESSION, CKA_CLASS, CKO_PRIVATE_KEY, CKM_SHA256_RSA_PKCS, CKM_SHA256
import binascii
def request_signature(payload):
"""
Request the HSM for a signature of the payload.
"""
# This should be your CU username and password formatted like this 'user_name:password'.
hsm_credentials = os.getenv('HSM_CREDENTIALS')
# This will be the data you want to sign.
session = create_hsm_session()
private_key = login_hsm_get_key(session, hsm_credentials)
signature = sign_payload(session, payload, private_key)
session.logout()
session.closeSession()
return signature
def create_hsm_session():
"""
Creates a HSM session and returns the session.
:return: The HSM session.
"""
# Load PKCS#11 LIB.
pkcs11 = PyKCS11.PyKCS11Lib()
pkcs11.load('/opt/cloudhsm/lib/libcloudhsm_pkcs11.so')
try:
# Get first slot as CloudHSM only has one slot.
slot = pkcs11.getSlotList()[0]
# Create Session.
session = pkcs11.openSession(slot, CKF_RW_SESSION)
return session
except PyKCS11.PyKCS11Error as exc:
return {"ERROR": f"PKCS#11 Error when creating session.{str(exc)}"}
def login_hsm_get_key(session, credentials):
""""
Logs in to HSM with credentials returns users private key.
:param session: The HSM session.
:param credentials: The credentials to login to the HSM.
:return: The users private key.
"""
try:
# Login to HSM.
session.login(credentials)
# Get private key for user.
private_key = session.findObjects([(CKA_CLASS, CKO_PRIVATE_KEY)])[0]
return private_key
except PyKCS11.PyKCS11Error:
return {"ERROR": "PKCS#11 Error when logging in and getting private key."}
def sign_payload(session, payload, private_key):
"""
Signs a payload and returns a signed payload.
:param session: The HSM session.
:param payload: The payload to sign.
:param private_key: The private key to use.
:return: The signature.
"""
try:
# You can change this to desired mechanism such as 'CKM_SHA1_RSA_PKCS'.
mechanism = PyKCS11.Mechanism(CKM_SHA256_RSA_PKCS, None)
signature = session.sign(private_key, payload, mechanism)
return signature
except PyKCS11.PyKCS11Error as exc:
return {"ERROR": f"PKCS#11 Error when signing payload: {str(exc)}"}
I am relatively new to signing PDFs/the structure of digital signatures.
I am expecting AdobePDF to return “Unable to verify the signer” because we do not have AATL compatible certs yet, but I am only getting the following message from Adobe saying the certificate is corrupted/incomplete:
And the following output from the program run:
No digest status to report.
SignatureHandler reports corruption in the Contents of the digital signature.
Am I missing something glaring here?