Skip to content

Commit 2ddaaf9

Browse files
committed
Move _remove_sig out of top level namespace
Also sort imports with isort and use standard flake8 configuration
1 parent f783e93 commit 2ddaaf9

File tree

6 files changed

+137
-77
lines changed

6 files changed

+137
-77
lines changed

setup.cfg

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
universal=1
33
[flake8]
44
max-line-length=120
5-
ignore: E301, E302, E305, E401, E226, F841
65
[coverage:run]
76
omit =
87
signxml/__pyinstaller/*

signxml/__init__.py

Lines changed: 36 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
1-
from base64 import b64encode, b64decode
1+
from base64 import b64decode, b64encode
2+
from collections import namedtuple
23
from enum import Enum
34

4-
from lxml import etree
5-
from lxml.etree import Element, SubElement
6-
5+
from cryptography.hazmat.backends import default_backend
76
from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa, utils
87
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
9-
from cryptography.hazmat.primitives.hashes import Hash, SHA1, SHA224, SHA256, SHA384, SHA512
8+
from cryptography.hazmat.primitives.hashes import SHA1, SHA224, SHA256, SHA384, SHA512, Hash
109
from cryptography.hazmat.primitives.serialization import load_der_public_key
11-
from cryptography.hazmat.backends import default_backend
10+
from lxml import etree
11+
from lxml.etree import Element, SubElement
1212

13-
from .exceptions import InvalidSignature, InvalidDigest, InvalidInput, InvalidCertificate # noqa
14-
from .util import (bytes_to_long, long_to_bytes, strip_pem_header, add_pem_header, ensure_bytes, ensure_str, Namespace,
15-
XMLProcessor, iterate_pem, verify_x509_cert_chain, bits_to_bytes_unit)
16-
from collections import namedtuple
13+
from .exceptions import InvalidCertificate, InvalidDigest, InvalidInput, InvalidSignature # noqa
14+
from .util import (
15+
Namespace,
16+
XMLProcessor,
17+
_remove_sig,
18+
add_pem_header,
19+
bits_to_bytes_unit,
20+
bytes_to_long,
21+
ensure_bytes,
22+
ensure_str,
23+
iterate_pem,
24+
long_to_bytes,
25+
strip_pem_header,
26+
verify_x509_cert_chain,
27+
)
1728

1829
methods = Enum("Methods", "enveloped enveloping detached")
1930

@@ -27,46 +38,18 @@
2738
xenc11="http://www.w3.org/2009/xmlenc11#"
2839
)
2940

41+
3042
def ds_tag(tag):
3143
return "{" + namespaces.ds + "}" + tag
3244

45+
3346
def dsig11_tag(tag):
3447
return "{" + namespaces.dsig11 + "}" + tag
3548

49+
3650
def ec_tag(tag):
3751
return "{" + namespaces.ec + "}" + tag
3852

39-
def _remove_sig(signature, idempotent=False):
40-
"""
41-
Remove the signature node from its parent, keeping any tail element.
42-
This is needed for eneveloped signatures.
43-
44-
:param signature: Signature to remove from payload
45-
:type signature: XML ElementTree Element
46-
:param idempotent:
47-
If True, don't raise an error if signature is already detached from parent.
48-
:type idempotent: boolean
49-
"""
50-
try:
51-
signaturep = next(signature.iterancestors())
52-
except StopIteration:
53-
if idempotent:
54-
return
55-
raise ValueError("Can't remove the root signature node")
56-
if signature.tail is not None:
57-
try:
58-
signatures = next(signature.itersiblings(preceding=True))
59-
except StopIteration:
60-
if signaturep.text is not None:
61-
signaturep.text = signaturep.text + signature.tail
62-
else:
63-
signaturep.text = signature.tail
64-
else:
65-
if signatures.tail is not None:
66-
signatures.tail = signatures.tail + signature.tail
67-
else:
68-
signatures.tail = signature.tail
69-
signaturep.remove(signature)
7053

7154
class VerifyResult(namedtuple("VerifyResult", "signed_data signed_xml signature_xml")):
7255
"""
@@ -84,6 +67,7 @@ class VerifyResult(namedtuple("VerifyResult", "signed_data signed_xml signature_
8467
verified_data = signxml.XMLVerifier().verify(input_data).signed_xml
8568
"""
8669

70+
8771
class XMLSignatureProcessor(XMLProcessor):
8872
schema_file = "xmldsig1-schema.xsd"
8973

@@ -245,6 +229,7 @@ def _resolve_reference(self, doc_root, reference, uri_resolver=None):
245229
raise InvalidInput("Unable to resolve reference URI: {}".format(uri))
246230
return result
247231

232+
248233
class XMLSigner(XMLSignatureProcessor):
249234
"""
250235
Create a new XML Signature Signer object, which can be used to hold configuration information and sign multiple
@@ -427,7 +412,7 @@ def sign(self, data, key=None, passphrase=None, cert=None, reference_uri=None, k
427412
if isinstance(cert, (str, bytes)):
428413
x509_certificate.text = strip_pem_header(cert)
429414
else:
430-
from OpenSSL.crypto import dump_certificate, FILETYPE_PEM
415+
from OpenSSL.crypto import FILETYPE_PEM, dump_certificate
431416
x509_certificate.text = strip_pem_header(dump_certificate(FILETYPE_PEM, cert))
432417
else:
433418
sig_root.append(key_info)
@@ -568,13 +553,14 @@ def _serialize_key_value(self, key, key_info_element):
568553
e.text = ensure_str(b64encode(long_to_bytes(getattr(key_params, field))))
569554
elif self.sign_alg.startswith("ecdsa-"):
570555
ec_key_value = SubElement(key_value, dsig11_tag("ECKeyValue"), nsmap=dict(dsig11=namespaces.dsig11))
571-
named_curve = SubElement(ec_key_value, dsig11_tag("NamedCurve"),
556+
named_curve = SubElement(ec_key_value, dsig11_tag("NamedCurve"), # noqa:F841
572557
URI=self.known_ecdsa_curve_oids[key.curve.name])
573558
public_key = SubElement(ec_key_value, dsig11_tag("PublicKey"))
574559
x = key.public_key().public_numbers().x
575560
y = key.public_key().public_numbers().y
576561
public_key.text = ensure_str(b64encode(long_to_bytes(4) + long_to_bytes(x) + long_to_bytes(y)))
577562

563+
578564
class XMLVerifier(XMLSignatureProcessor):
579565
"""
580566
Create a new XML Signature Verifier object, which can be used to hold configuration information and verify multiple
@@ -596,8 +582,8 @@ def _verify_signature_with_pubkey(self, signed_info_c14n, raw_signature, key_val
596582
named_curve = self._find(ec_key_value, "NamedCurve", namespace="dsig11")
597583
public_key = self._find(ec_key_value, "PublicKey", namespace="dsig11")
598584
key_data = b64decode(public_key.text)[1:]
599-
x = bytes_to_long(key_data[:len(key_data)//2])
600-
y = bytes_to_long(key_data[len(key_data)//2:])
585+
x = bytes_to_long(key_data[:len(key_data) // 2])
586+
y = bytes_to_long(key_data[len(key_data) // 2:])
601587
curve_class = self.known_ecdsa_curves[named_curve.get("URI")]
602588
key = ec.EllipticCurvePublicNumbers(x=x, y=y, curve=curve_class()).public_key(backend=default_backend())
603589
elif not isinstance(key, ec.EllipticCurvePublicKey):
@@ -818,7 +804,9 @@ def verify(self, data, require_x509=True, x509_cert=None, cert_subject_name=None
818804
inclusive_ns_prefixes=inclusive_ns_prefixes)
819805

820806
if x509_data is not None or self.require_x509:
821-
from OpenSSL.crypto import load_certificate, X509, FILETYPE_PEM, verify, Error as OpenSSLCryptoError
807+
from OpenSSL.crypto import FILETYPE_PEM, X509
808+
from OpenSSL.crypto import Error as OpenSSLCryptoError
809+
from OpenSSL.crypto import load_certificate, verify
822810

823811
if self.x509_cert is None:
824812
if x509_data is None:
@@ -939,8 +927,8 @@ def check_key_value_matches_cert_public_key(self, key_value, public_key, signatu
939927
named_curve = self._find(ec_key_value, "NamedCurve", namespace="dsig11")
940928
public_key = self._find(ec_key_value, "PublicKey", namespace="dsig11")
941929
key_data = b64decode(public_key.text)[1:]
942-
x = bytes_to_long(key_data[:len(key_data)//2])
943-
y = bytes_to_long(key_data[len(key_data)//2:])
930+
x = bytes_to_long(key_data[:len(key_data) // 2])
931+
y = bytes_to_long(key_data[len(key_data) // 2:])
944932
curve_class = self.known_ecdsa_curves[named_curve.get("URI")]
945933

946934
pubk_curve = public_key.to_cryptography_key().public_numbers().curve

signxml/exceptions.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,28 @@
44

55
import cryptography.exceptions
66

7+
78
class InvalidSignature(cryptography.exceptions.InvalidSignature):
89
"""
910
Raised when signature validation fails.
1011
"""
1112

13+
1214
class InvalidDigest(InvalidSignature):
1315
"""
1416
Raised when digest validation fails (causing the signature to be untrusted).
1517
"""
1618

19+
1720
class InvalidCertificate(InvalidSignature):
1821
"""
1922
Raised when certificate validation fails.
2023
"""
2124

25+
2226
class InvalidInput(ValueError):
2327
pass
2428

29+
2530
class RedundantCert(Exception):
2631
pass

signxml/util/__init__.py

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@
55
"""
66

77
import math
8-
import os, sys, re, struct, textwrap
8+
import os
9+
import re
10+
import struct
11+
import sys
12+
import textwrap
13+
from base64 import b64decode, b64encode
914
from xml.etree import ElementTree as stdlibElementTree
10-
from base64 import b64encode, b64decode
1115

1216
from lxml import etree
1317

14-
from ..exceptions import RedundantCert, InvalidCertificate, InvalidInput
18+
from ..exceptions import InvalidCertificate, InvalidInput, RedundantCert
1519

1620
USING_PYTHON2 = True if sys.version_info < (3, 0) else False
1721

@@ -168,8 +172,8 @@ def get_root(self, data):
168172

169173

170174
def hmac_sha1(key, message):
171-
from cryptography.hazmat.primitives import hashes, hmac
172175
from cryptography.hazmat.backends import default_backend
176+
from cryptography.hazmat.primitives import hashes, hmac
173177
hasher = hmac.HMAC(key, hashes.SHA1(), backend=default_backend())
174178
hasher.update(message)
175179
return hasher.finalize()
@@ -208,7 +212,8 @@ def p_sha1(client_b64_bytes, server_b64_bytes):
208212

209213

210214
def _add_cert_to_store(store, cert):
211-
from OpenSSL.crypto import X509StoreContext, X509StoreContextError, Error as OpenSSLCryptoError
215+
from OpenSSL.crypto import Error as OpenSSLCryptoError
216+
from OpenSSL.crypto import X509StoreContext, X509StoreContextError
212217
try:
213218
X509StoreContext(store, cert).verify_certificate()
214219
except X509StoreContextError as e:
@@ -257,3 +262,36 @@ def verify_x509_cert_chain(cert_chain, ca_pem_file=None, ca_path=None):
257262
else:
258263
raise last_error
259264
return end_of_chain
265+
266+
267+
def _remove_sig(signature, idempotent=False):
268+
"""
269+
Remove the signature node from its parent, keeping any tail element.
270+
This is needed for eneveloped signatures.
271+
272+
:param signature: Signature to remove from payload
273+
:type signature: XML ElementTree Element
274+
:param idempotent:
275+
If True, don't raise an error if signature is already detached from parent.
276+
:type idempotent: boolean
277+
"""
278+
try:
279+
signaturep = next(signature.iterancestors())
280+
except StopIteration:
281+
if idempotent:
282+
return
283+
raise ValueError("Can't remove the root signature node")
284+
if signature.tail is not None:
285+
try:
286+
signatures = next(signature.itersiblings(preceding=True))
287+
except StopIteration:
288+
if signaturep.text is not None:
289+
signaturep.text = signaturep.text + signature.tail
290+
else:
291+
signaturep.text = signature.tail
292+
else:
293+
if signatures.tail is not None:
294+
signatures.tail = signatures.tail + signature.tail
295+
else:
296+
signatures.tail = signature.tail
297+
signaturep.remove(signature)

test/generate_125_example.py

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
import os.path
22
from base64 import b64encode
33

4-
from lxml import etree
5-
from lxml.etree import Element, SubElement
6-
4+
from cryptography.hazmat.backends import default_backend
75
from cryptography.hazmat.primitives.asymmetric import ec
86
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
9-
from cryptography.hazmat.backends import default_backend
10-
11-
from signxml import XMLSignatureProcessor, InvalidInput, namespaces, iterate_pem, ds_tag, _remove_sig, \
12-
ensure_str, long_to_bytes, strip_pem_header, dsig11_tag
7+
from lxml import etree
8+
from lxml.etree import Element, SubElement
9+
from signxml import (
10+
InvalidInput,
11+
XMLSignatureProcessor,
12+
_remove_sig,
13+
ds_tag,
14+
dsig11_tag,
15+
ensure_str,
16+
iterate_pem,
17+
long_to_bytes,
18+
namespaces,
19+
strip_pem_header,
20+
)
1321

1422

1523
class XMLEnvelopedEnvelopingSigner(XMLSignatureProcessor):
@@ -96,7 +104,9 @@ def sign(self, data, key=None, passphrase=None, cert=None, key_name=None, key_in
96104
sig_root.append(signature_value_element)
97105
elif any(self.sign_alg.startswith(i) for i in ["dsa-", "rsa-", "ecdsa-"]):
98106
if isinstance(key, (str, bytes)):
99-
from cryptography.hazmat.primitives.serialization import load_pem_private_key
107+
from cryptography.hazmat.primitives.serialization import (
108+
load_pem_private_key,
109+
)
100110
key = load_pem_private_key(key, password=passphrase, backend=default_backend())
101111

102112
hash_alg = self._get_signature_digest_method_by_tag(self.sign_alg)
@@ -133,7 +143,7 @@ def sign(self, data, key=None, passphrase=None, cert=None, key_name=None, key_in
133143
if isinstance(cert, (str, bytes)):
134144
x509_certificate.text = strip_pem_header(cert)
135145
else:
136-
from OpenSSL.crypto import dump_certificate, FILETYPE_PEM
146+
from OpenSSL.crypto import FILETYPE_PEM, dump_certificate
137147
x509_certificate.text = strip_pem_header(dump_certificate(FILETYPE_PEM, cert))
138148
else:
139149
sig_root.append(key_info)
@@ -191,19 +201,19 @@ def _unpack(self, data):
191201

192202
def _build_sig(self, sig_root, reference_uris, c14n_inputs):
193203
signed_info = SubElement(sig_root, ds_tag("SignedInfo"), nsmap=self.namespaces)
194-
c14n_method = SubElement(signed_info, ds_tag("CanonicalizationMethod"), Algorithm=self.c14n_alg)
204+
c14n_method = SubElement(signed_info, ds_tag("CanonicalizationMethod"), Algorithm=self.c14n_alg) # noqa:F841
195205
if self.sign_alg.startswith("hmac-"):
196206
algorithm_id = self.known_hmac_digest_tags[self.sign_alg]
197207
else:
198208
algorithm_id = self.known_signature_digest_tags[self.sign_alg]
199-
signature_method = SubElement(signed_info, ds_tag("SignatureMethod"), Algorithm=algorithm_id)
209+
signature_method = SubElement(signed_info, ds_tag("SignatureMethod"), Algorithm=algorithm_id) # noqa:F841
200210
for i, reference_uri in enumerate(reference_uris):
201211
reference = SubElement(signed_info, ds_tag("Reference"), URI=reference_uri)
202212
if i == 0:
203213
transforms = SubElement(reference, ds_tag("Transforms"))
204214
SubElement(transforms, ds_tag("Transform"), Algorithm=namespaces.ds + "enveloped-signature")
205215
SubElement(transforms, ds_tag("Transform"), Algorithm=self.c14n_alg)
206-
digest_method = SubElement(reference, ds_tag("DigestMethod"),
216+
digest_method = SubElement(reference, ds_tag("DigestMethod"), # noqa:F841
207217
Algorithm=self.known_digest_tags[self.digest_alg])
208218
digest_value = SubElement(reference, ds_tag("DigestValue"))
209219
payload_c14n = self._c14n(c14n_inputs[i], algorithm=self.c14n_alg)
@@ -233,7 +243,7 @@ def _serialize_key_value(self, key, key_info_element):
233243
e.text = ensure_str(b64encode(long_to_bytes(getattr(key_params, field))))
234244
elif self.sign_alg.startswith("ecdsa-"):
235245
ec_key_value = SubElement(key_value, dsig11_tag("ECKeyValue"), nsmap=dict(dsig11=namespaces.dsig11))
236-
named_curve = SubElement(ec_key_value, dsig11_tag("NamedCurve"),
246+
named_curve = SubElement(ec_key_value, dsig11_tag("NamedCurve"), # noqa:F841
237247
URI=self.known_ecdsa_curve_oids[key.curve.name])
238248
public_key = SubElement(ec_key_value, dsig11_tag("PublicKey"))
239249
x = key.public_key().public_numbers().x

0 commit comments

Comments
 (0)