1212from .algorithms import (
1313 CanonicalizationMethod ,
1414 DigestAlgorithm ,
15+ SignatureConstructionMethod ,
1516 SignatureMethod ,
16- SignatureType ,
1717 digest_algorithm_implementations ,
1818)
1919from .exceptions import InvalidInput
@@ -59,9 +59,8 @@ class XMLSigner(XMLSignatureProcessor):
5959 pieces of data.
6060
6161 :param method:
62- ``signxml.methods.enveloped``, ``signxml.methods.enveloping``, or ``signxml.methods.detached``. See the list
63- of signature types under `XML Signature Syntax and Processing Version 2.0, Definitions
64- <http://www.w3.org/TR/xmldsig-core2/#sec-Definitions>`_.
62+ ``signxml.methods.enveloped``, ``signxml.methods.enveloping``, or ``signxml.methods.detached``. See
63+ :class:`SignatureConstructionMethod` for details.
6564 :param signature_algorithm:
6665 Algorithm that will be used to generate the signature, composed of the signature algorithm and the digest
6766 algorithm, separated by a hyphen. All algorithm IDs listed under the `Algorithm Identifiers and
@@ -72,16 +71,32 @@ class XMLSigner(XMLSignatureProcessor):
7271 <http://www.w3.org/TR/xmldsig-core1/#sec-AlgID>`_ section of the XML Signature 1.1 standard are supported.
7372 """
7473
74+ signature_annotators : List
75+ """
76+ A list of callables that will be called at signature creation time to annotate the content to be signed before
77+ signing. You can use this to register a custom signature decorator as follows:
78+
79+ .. code-block:: python
80+
81+ def my_annotator(sig_root, signing_settings):
82+ ...
83+ sig_root.append(my_custom_node)
84+
85+ signer = XMLSigner()
86+ signer.signature_annotators.append(my_annotator)
87+ signed = signer.sign(data, ...)
88+ """
89+
7590 def __init__ (
7691 self ,
77- method : SignatureType = SignatureType .enveloped ,
92+ method : SignatureConstructionMethod = SignatureConstructionMethod .enveloped ,
7893 signature_algorithm : Union [SignatureMethod , str ] = SignatureMethod .RSA_SHA256 ,
7994 digest_algorithm : Union [DigestAlgorithm , str ] = DigestAlgorithm .SHA256 ,
8095 c14n_algorithm = CanonicalizationMethod .CANONICAL_XML_1_1 ,
8196 ):
82- if method is None or method not in SignatureType :
83- raise InvalidInput (f"Unknown signature method { method } " )
84- self .signature_type = method
97+ if method is None or method not in SignatureConstructionMethod :
98+ raise InvalidInput (f"Unknown signature construction method { method } " )
99+ self .construction_method = method
85100 if isinstance (signature_algorithm , str ) and "#" not in signature_algorithm :
86101 self .sign_alg = SignatureMethod .from_fragment (signature_algorithm )
87102 else :
@@ -108,7 +123,7 @@ def sign(
108123 always_add_key_value : bool = False ,
109124 inclusive_ns_prefixes : Optional [List [str ]] = None ,
110125 signature_properties = None ,
111- ):
126+ ) -> _Element :
112127 """
113128 Sign the data and return the root element of the resulting XML tree.
114129
@@ -168,7 +183,7 @@ def sign(
168183
169184 To specify the location of an enveloped signature within **data**, insert a
170185 ``<ds:Signature Id="placeholder"></ds:Signature>`` element in **data** (where
171- "ds" is the " http://www.w3.org/2000/09/xmldsig#" namespace). This element will
186+ "ds" is the `` http://www.w3.org/2000/09/xmldsig#`` namespace). This element will
172187 be replaced by the generated signature, and excised when generating the digest.
173188 """
174189 if id_attribute is not None :
@@ -199,7 +214,7 @@ def sign(
199214
200215 sig_root , doc_root , c14n_inputs , references = self ._unpack (data , input_references )
201216
202- if self .signature_type == SignatureType .detached and signature_properties is not None :
217+ if self .construction_method == SignatureConstructionMethod .detached and signature_properties is not None :
203218 references .append (XMLSignatureReference (URI = "#prop" ))
204219 if signature_properties is not None and not isinstance (signature_properties , list ):
205220 signature_properties = [signature_properties ]
@@ -246,14 +261,14 @@ def sign(
246261 else :
247262 raise NotImplementedError ()
248263
249- if self .signature_type == SignatureType .enveloping :
264+ if self .construction_method == SignatureConstructionMethod .enveloping :
250265 for c14n_input in c14n_inputs :
251266 doc_root .append (c14n_input )
252267
253- if self .signature_type == SignatureType .detached and signature_properties is not None :
268+ if self .construction_method == SignatureConstructionMethod .detached and signature_properties is not None :
254269 sig_root .append (signature_properties_el )
255270
256- return doc_root if self .signature_type == SignatureType .enveloped else sig_root
271+ return doc_root if self .construction_method == SignatureConstructionMethod .enveloped else sig_root
257272
258273 def _preprocess_reference_uri (self , reference_uris ):
259274 if reference_uris is None :
@@ -298,7 +313,7 @@ def _get_c14n_inputs_from_references(self, doc_root, references: List[XMLSignatu
298313
299314 def _unpack (self , data , references : List [XMLSignatureReference ]):
300315 sig_root = Element (ds_tag ("Signature" ), nsmap = self .namespaces )
301- if self .signature_type == SignatureType .enveloped :
316+ if self .construction_method == SignatureConstructionMethod .enveloped :
302317 if isinstance (data , (str , bytes )):
303318 raise InvalidInput ("When using enveloped signature, **data** must be an XML element" )
304319 doc_root = self .get_root (data )
@@ -328,7 +343,7 @@ def _unpack(self, data, references: List[XMLSignatureReference]):
328343 payload_id = c14n_input .get ("Id" , c14n_input .get ("ID" ))
329344 uri = "#{}" .format (payload_id ) if payload_id is not None else ""
330345 references .append (XMLSignatureReference (URI = uri ))
331- elif self .signature_type == SignatureType .detached :
346+ elif self .construction_method == SignatureConstructionMethod .detached :
332347 doc_root = self .get_root (data )
333348 if references is None :
334349 uri = "#{}" .format (data .get ("Id" , data .get ("ID" , "object" )))
@@ -338,7 +353,7 @@ def _unpack(self, data, references: List[XMLSignatureReference]):
338353 c14n_inputs , references = self ._get_c14n_inputs_from_references (doc_root , references )
339354 except InvalidInput : # Dummy reference URI
340355 c14n_inputs = [self .get_root (data )]
341- elif self .signature_type == SignatureType .enveloping :
356+ elif self .construction_method == SignatureConstructionMethod .enveloping :
342357 doc_root = sig_root
343358 c14n_inputs = [Element (ds_tag ("Object" ), nsmap = self .namespaces , Id = "object" )]
344359 if isinstance (data , (str , bytes )):
@@ -362,7 +377,7 @@ def _build_sig(self, sig_root, references, c14n_inputs, inclusive_ns_prefixes):
362377 reference .inclusive_ns_prefixes = inclusive_ns_prefixes
363378 reference_node = SubElement (signed_info , ds_tag ("Reference" ), URI = reference .URI )
364379 transforms = SubElement (reference_node , ds_tag ("Transforms" ))
365- if self .signature_type == SignatureType .enveloped :
380+ if self .construction_method == SignatureConstructionMethod .enveloped :
366381 SubElement (transforms , ds_tag ("Transform" ), Algorithm = namespaces .ds + "enveloped-signature" )
367382 SubElement (transforms , ds_tag ("Transform" ), Algorithm = reference .c14n_method .value )
368383 else :
0 commit comments