pyhanko.sign.signers.cms_embedder module

This module describes and implements the low-level PdfCMSEmbedder protocol for embedding CMS payloads into PDF signature objects.

class pyhanko.sign.signers.cms_embedder.PdfCMSEmbedder(new_field_spec: Optional[SigFieldSpec] = None)

Bases: object

Low-level class that handles embedding CMS objects into PDF signature fields.

It also takes care of appearance generation and DocMDP configuration, but does not otherwise offer any of the conveniences of PdfSigner.

Parameters

new_field_specSigFieldSpec to use when creating new fields on-the-fly.

write_cms(field_name: str, writer: BasePdfFileWriter, existing_fields_only=False)

New in version 0.3.0.

Changed in version 0.7.0: Digest wrapped in PreparedByteRangeDigest in step 3; output returned in step 3 instead of step 4.

This method returns a generator coroutine that controls the process of embedding CMS data into a PDF signature field. Can be used for both timestamps and regular signatures.

Danger

This is a very low-level interface that performs virtually no error checking, and is intended to be used in situations where the construction of the CMS object to be embedded is not under the caller’s control (e.g. a remote signer that produces full-fledged CMS objects).

In almost every other case, you’re better of using PdfSigner instead, with a custom Signer implementation to handle the cryptographic operations if necessary.

The coroutine follows the following specific protocol.

  1. First, it retrieves or creates the signature field to embed the CMS object in, and yields a reference to said field.

  2. The caller should then send in a SigObjSetup object, which is subsequently processed by the coroutine. For convenience, the coroutine will then yield a reference to the signature dictionary (as embedded in the PDF writer).

  3. Next, the caller should send a SigIOSetup object, describing how the resulting document should be hashed and written to the output. The coroutine will write the entire document with a placeholder region reserved for the signature and compute the document’s hash and yield it to the caller. It will then yield a prepared_digest, output tuple, where prepared_digest is a PreparedByteRangeDigest object containing the document digest and the relevant offsets, and output is the output stream to which the document to be signed was written.

    From this point onwards, no objects may be changed or added to the IncrementalPdfFileWriter currently in use.

  4. Finally, the caller should pass in a CMS object to place inside the signature dictionary. The CMS object can be supplied as a raw bytes object, or an asn1crypto-style object. The coroutine’s final yield is the value of the signature dictionary’s /Contents entry, given as a hexadecimal string.

Caution

It is the caller’s own responsibility to ensure that enough room is available in the placeholder signature object to contain the final CMS object.

Parameters
  • field_name – The name of the field to fill in. This should be a field of type /Sig.

  • writer – An IncrementalPdfFileWriter containing the document to sign.

  • existing_fields_only – If True, never create a new empty signature field to contain the signature. If False, a new field may be created if no field matching field_name exists.

Returns

A generator coroutine implementing the protocol described above.

class pyhanko.sign.signers.cms_embedder.SigMDPSetup(md_algorithm: str, certify: bool = False, field_lock: Union[pyhanko.sign.fields.FieldMDPSpec, NoneType] = None, docmdp_perms: Union[pyhanko.sign.fields.MDPPerm, NoneType] = None)

Bases: object

md_algorithm: str

Message digest algorithm to write into the signature reference dictionary, if one is written at all.

Warning

It is the caller’s responsibility to make sure that this value agrees with the value embedded into the CMS object, and with the algorithm used to hash the document. The low-level PdfCMSEmbedder API will simply take it at face value.

certify: bool = False

Sign with an author (certification) signature, as opposed to an approval signature. A document can contain at most one such signature, and it must be the first one.

field_lock: Optional[FieldMDPSpec] = None

Field lock information to write to the signature reference dictionary.

docmdp_perms: Optional[MDPPerm] = None

DocMDP permissions to write to the signature reference dictionary.

apply(sig_obj_ref, writer)

Apply the settings to a signature object.

Danger

This method is internal API.

class pyhanko.sign.signers.cms_embedder.SigObjSetup(sig_placeholder: PdfSignedData, mdp_setup: Optional[SigMDPSetup] = None, appearance_setup: Optional[SigAppearanceSetup] = None)

Bases: object

Describes the signature dictionary to be embedded as the form field’s value.

sig_placeholder: PdfSignedData

Bare-bones placeholder object, usually of type SignatureObject or DocumentTimestamp.

In particular, this determines the number of bytes to allocate for the CMS object.

mdp_setup: Optional[SigMDPSetup] = None

Optional DocMDP settings, see SigMDPSetup.

appearance_setup: Optional[SigAppearanceSetup] = None

Optional appearance settings, see SigAppearanceSetup.

class pyhanko.sign.signers.cms_embedder.SigAppearanceSetup(style: BaseStampStyle, timestamp: datetime, name: str, text_params: Optional[dict] = None)

Bases: object

Signature appearance configuration.

Part of the low-level PdfCMSEmbedder API, see SigObjSetup.

style: BaseStampStyle

Stamp style to use to generate the appearance.

timestamp: datetime

Timestamp to show in the signature appearance.

name: str

Signer name to show in the signature appearance.

text_params: dict = None

Additional text interpolation parameters to pass to the underlying stamp style.

apply(sig_annot, writer)

Apply the settings to an annotation.

Danger

This method is internal API.

class pyhanko.sign.signers.cms_embedder.SigIOSetup(md_algorithm: str, in_place: bool = False, chunk_size: int = 4096, output: Optional[IO] = None)

Bases: object

I/O settings for writing signed PDF documents.

Objects of this type are used in the penultimate phase of the PdfCMSEmbedder protocol.

md_algorithm: str

Message digest algorithm to use to compute the document hash. It should be supported by pyca/cryptography.

Warning

This is also the message digest algorithm that should appear in the corresponding signerInfo entry in the CMS object that ends up being embedded in the signature field.

in_place: bool = False

Sign the input in-place. If False, write output to a BytesIO object, or output if the latter is not None.

chunk_size: int = 4096

Size of the internal buffer (in bytes) used to feed data to the message digest function if the input stream does not support memoryview.

output: Optional[IO] = None

Write the output to the specified output stream. If None, write to a new BytesIO object. Default is None.