Indian eSign (CCA)#
ATick supports the CCA eSign Online Electronic Signature Service for every API version (v1.x … v3.x). The flow is the same across versions — only the request XML attributes differ.
PDF -> SHA-256 of the ByteRange (the InputHash, hex)
-> build the <Esign …> request XML for your version, put the InputHash in <InputHash>
-> sign the request XML (your managex-xml-sdk) [enveloped W3C XML-DSig]
-> POST it (multipart/form-data) to the ESP
-> EsignResp -> <DocSignature> (rawrsa / pkcs7 / pkcs7Pdf / pkcs7complete)
-> embed it into the PDF
Step 1 — prepare + hash#
prepared, ctx = atick.prepare_deferred_multi(
pdf, atick.Style(cn="…", always_check=True),
[(1, (40, 640, 300, 750)), (2, (320, 380, 560, 490))], # signature box on each page
mode="single", sub_filter="adbe.pkcs7.detached",
certify=atick.Certify.FORM_FILLING_ANNOTATIONS, # CFA -> later timestamp won't invalidate
contents_size=60000, # room for chain + revocation + timestamp
)
input_hash_hex = bytes(ctx["digest"]).hex() # goes into <InputHash>
data = bytes(ctx["data"]) # the exact bytes the ESP signs
Step 2 — sign the request XML with managex-xml-sdk#
Important
managex-xml-sdk needs a trusted-roots folder. Before it will sign, it validates your ASP
certificate against the CA root certificate(s) in the folder you give as
ValidationConfig(trusted_roots_folder=…). That folder must exist and contain the CA root
certificate(s) as PEM files — if the folder is missing or empty, signing the request fails and
eSign will not work. Put your CA’s root (and intermediate) certificates there as .pem files.
import managex_xml_sdk as mx
from managex_xml_sdk.models.certificate_models import PFXConfig, ValidationConfig
request = (f'<Esign ver="2.1" sc="Y" ts="…" txn="TXN1" ekycIdType="A" aspId="…" AuthMode="1" '
f'responseSigType="pkcs7Pdf" responseUrl="https://…/"><Docs>'
f'<InputHash id="1" hashAlgorithm="SHA256" docInfo="Agreement">{input_hash_hex}</InputHash>'
f'</Docs></Esign>')
signer = mx.PFXSigner(PFXConfig(method="pfx", pfx_file="asp.pfx", password="…",
validation_config=ValidationConfig(trusted_roots_folder="roots")))
params = mx.SignatureEnvelopeParameters(
signature_info=mx.SignatureInfo(signature_algorithm=mx.SignatureAlgorithm.RSA_SHA256),
reference_info=mx.ReferenceInfo(uri="", transforms=[mx.TransformAlgorithm.ENVELOPED_SIGNATURE]),
key_info=mx.KeyInfo(include_subject_name=True, include_certificate=True))
signed_request = signer.sign_xml_content(request.encode(), params) # POST this to the ESP
Step 3 — embed the ESP response#
import base64, xml.etree.ElementTree as ET
root = ET.fromstring(esign_response_xml)
doc_sig = base64.b64decode(next(e.text for e in root.iter() if e.tag.endswith("DocSignature")))
signed = atick.embed(prepared, doc_sig) # pkcs7 / pkcs7Pdf / pkcs7complete (a full CMS)
# rawrsa: atick.embed_rawrsa(prepared, doc_sig, user_cert)
pkcs7Pdf and pkcs7complete responses already carry the full chain, the revocation (under
pdfRevocationInfoArchival) and a CA timestamp — so the embedded signature is LTV-complete and
timestamped out of the box.
responseSigType#
Value |
Returns |
Embed with |
|---|---|---|
|
a raw RSA signature + the signer cert |
|
|
a CMS, signer cert only (no revocation) |
|
|
a CMS, full chain + CRL/OCSP (signed attr) + timestamp |
|
|
a CMS, full chain + revocation (unsigned attr) |
|
Simulating the ESP for testing#
atick.cms_pfx(data, pfx, pw, revocation=True, timestamp=True) produces a pkcs7Pdf-style CMS, and
atick.sign_hash_pfx(data, pfx, pw) a rawrsa response — so you can run the whole flow end-to-end
without a live ESP. See examples/esign/.
Command line#
atick esign-prepare in.pdf prepared.pdf --certify form-annots # prints the InputHash
# sign the request XML (managex-xml-sdk) + POST to the ESP, save the response
atick esign-embed prepared.pdf response.xml signed.pdf