12
12
from .algorithms import (
13
13
CanonicalizationMethod ,
14
14
DigestAlgorithm ,
15
+ SignatureConstructionMethod ,
15
16
SignatureMethod ,
16
- SignatureType ,
17
17
digest_algorithm_implementations ,
18
18
)
19
19
from .exceptions import InvalidInput
@@ -59,9 +59,8 @@ class XMLSigner(XMLSignatureProcessor):
59
59
pieces of data.
60
60
61
61
: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.
65
64
:param signature_algorithm:
66
65
Algorithm that will be used to generate the signature, composed of the signature algorithm and the digest
67
66
algorithm, separated by a hyphen. All algorithm IDs listed under the `Algorithm Identifiers and
@@ -72,16 +71,32 @@ class XMLSigner(XMLSignatureProcessor):
72
71
<http://www.w3.org/TR/xmldsig-core1/#sec-AlgID>`_ section of the XML Signature 1.1 standard are supported.
73
72
"""
74
73
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
+
75
90
def __init__ (
76
91
self ,
77
- method : SignatureType = SignatureType .enveloped ,
92
+ method : SignatureConstructionMethod = SignatureConstructionMethod .enveloped ,
78
93
signature_algorithm : Union [SignatureMethod , str ] = SignatureMethod .RSA_SHA256 ,
79
94
digest_algorithm : Union [DigestAlgorithm , str ] = DigestAlgorithm .SHA256 ,
80
95
c14n_algorithm = CanonicalizationMethod .CANONICAL_XML_1_1 ,
81
96
):
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
85
100
if isinstance (signature_algorithm , str ) and "#" not in signature_algorithm :
86
101
self .sign_alg = SignatureMethod .from_fragment (signature_algorithm )
87
102
else :
@@ -108,7 +123,7 @@ def sign(
108
123
always_add_key_value : bool = False ,
109
124
inclusive_ns_prefixes : Optional [List [str ]] = None ,
110
125
signature_properties = None ,
111
- ):
126
+ ) -> _Element :
112
127
"""
113
128
Sign the data and return the root element of the resulting XML tree.
114
129
@@ -168,7 +183,7 @@ def sign(
168
183
169
184
To specify the location of an enveloped signature within **data**, insert a
170
185
``<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
172
187
be replaced by the generated signature, and excised when generating the digest.
173
188
"""
174
189
if id_attribute is not None :
@@ -199,7 +214,7 @@ def sign(
199
214
200
215
sig_root , doc_root , c14n_inputs , references = self ._unpack (data , input_references )
201
216
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 :
203
218
references .append (XMLSignatureReference (URI = "#prop" ))
204
219
if signature_properties is not None and not isinstance (signature_properties , list ):
205
220
signature_properties = [signature_properties ]
@@ -246,14 +261,14 @@ def sign(
246
261
else :
247
262
raise NotImplementedError ()
248
263
249
- if self .signature_type == SignatureType .enveloping :
264
+ if self .construction_method == SignatureConstructionMethod .enveloping :
250
265
for c14n_input in c14n_inputs :
251
266
doc_root .append (c14n_input )
252
267
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 :
254
269
sig_root .append (signature_properties_el )
255
270
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
257
272
258
273
def _preprocess_reference_uri (self , reference_uris ):
259
274
if reference_uris is None :
@@ -298,7 +313,7 @@ def _get_c14n_inputs_from_references(self, doc_root, references: List[XMLSignatu
298
313
299
314
def _unpack (self , data , references : List [XMLSignatureReference ]):
300
315
sig_root = Element (ds_tag ("Signature" ), nsmap = self .namespaces )
301
- if self .signature_type == SignatureType .enveloped :
316
+ if self .construction_method == SignatureConstructionMethod .enveloped :
302
317
if isinstance (data , (str , bytes )):
303
318
raise InvalidInput ("When using enveloped signature, **data** must be an XML element" )
304
319
doc_root = self .get_root (data )
@@ -328,7 +343,7 @@ def _unpack(self, data, references: List[XMLSignatureReference]):
328
343
payload_id = c14n_input .get ("Id" , c14n_input .get ("ID" ))
329
344
uri = "#{}" .format (payload_id ) if payload_id is not None else ""
330
345
references .append (XMLSignatureReference (URI = uri ))
331
- elif self .signature_type == SignatureType .detached :
346
+ elif self .construction_method == SignatureConstructionMethod .detached :
332
347
doc_root = self .get_root (data )
333
348
if references is None :
334
349
uri = "#{}" .format (data .get ("Id" , data .get ("ID" , "object" )))
@@ -338,7 +353,7 @@ def _unpack(self, data, references: List[XMLSignatureReference]):
338
353
c14n_inputs , references = self ._get_c14n_inputs_from_references (doc_root , references )
339
354
except InvalidInput : # Dummy reference URI
340
355
c14n_inputs = [self .get_root (data )]
341
- elif self .signature_type == SignatureType .enveloping :
356
+ elif self .construction_method == SignatureConstructionMethod .enveloping :
342
357
doc_root = sig_root
343
358
c14n_inputs = [Element (ds_tag ("Object" ), nsmap = self .namespaces , Id = "object" )]
344
359
if isinstance (data , (str , bytes )):
@@ -362,7 +377,7 @@ def _build_sig(self, sig_root, references, c14n_inputs, inclusive_ns_prefixes):
362
377
reference .inclusive_ns_prefixes = inclusive_ns_prefixes
363
378
reference_node = SubElement (signed_info , ds_tag ("Reference" ), URI = reference .URI )
364
379
transforms = SubElement (reference_node , ds_tag ("Transforms" ))
365
- if self .signature_type == SignatureType .enveloped :
380
+ if self .construction_method == SignatureConstructionMethod .enveloped :
366
381
SubElement (transforms , ds_tag ("Transform" ), Algorithm = namespaces .ds + "enveloped-signature" )
367
382
SubElement (transforms , ds_tag ("Transform" ), Algorithm = reference .c14n_method .value )
368
383
else :
0 commit comments