Skip to content

Commit 04a58d1

Browse files
committed
chore: Update to SignXML 4.0.0 version
- Updated error messages and expected exception in tests. - Updated `add_pem_cert_header_footer` and now `signxml.util.add_pem_header` returns a byte object. - Removed use of `crypto_utils._X509CertOpenSsl` in `verify_xml_signature` as SignXML has deprecated PyOpenSSL. Ref: https://app.shortcut.com/cordada/story/11838/ [sc-11838]
1 parent a694db1 commit 04a58d1

File tree

4 files changed

+71
-64
lines changed

4 files changed

+71
-64
lines changed

src/cl_sii/libs/crypto_utils.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,7 @@ def add_pem_cert_header_footer(pem_cert: bytes) -> bytes:
157157
"""
158158
pem_value_str = pem_cert.decode('ascii')
159159
# note: it would be great if 'add_pem_header' did not forcefully convert bytes to str.
160-
mod_pem_value_str = signxml.util.add_pem_header(pem_value_str)
161-
mod_pem_value: bytes = mod_pem_value_str.encode('ascii')
160+
mod_pem_value: bytes = signxml.util.add_pem_header(pem_value_str)
162161
return mod_pem_value
163162

164163

src/cl_sii/libs/xml_utils.py

+5-10
Original file line numberDiff line numberDiff line change
@@ -440,14 +440,8 @@ def verify_xml_signature(
440440
)
441441

442442
if isinstance(trusted_x509_cert, crypto_utils._X509CertOpenSsl):
443-
trusted_x509_cert_open_ssl = trusted_x509_cert
444-
elif isinstance(trusted_x509_cert, crypto_utils.X509Cert):
445-
trusted_x509_cert_open_ssl = crypto_utils._X509CertOpenSsl.from_cryptography(
446-
trusted_x509_cert
447-
)
448-
elif trusted_x509_cert is None:
449-
trusted_x509_cert_open_ssl = None
450-
else:
443+
trusted_x509_cert = trusted_x509_cert.to_cryptography()
444+
elif not (isinstance(trusted_x509_cert, crypto_utils.X509Cert) or trusted_x509_cert is None):
451445
# A 'crypto_utils._X509CertOpenSsl' is ok but we prefer 'crypto_utils.X509Cert'.
452446
raise TypeError("'trusted_x509_cert' must be a 'crypto_utils.X509Cert' instance, or None.")
453447

@@ -482,9 +476,10 @@ def verify_xml_signature(
482476
result = xml_verifier.verify(
483477
data=tmp_bytes,
484478
require_x509=True,
485-
x509_cert=trusted_x509_cert_open_ssl,
486-
ignore_ambiguous_key_info=True,
479+
x509_cert=trusted_x509_cert,
487480
expect_config=signxml.verifier.SignatureConfiguration(
481+
require_x509=True,
482+
ignore_ambiguous_key_info=True,
488483
signature_methods=frozenset([signxml.algorithms.SignatureMethod.RSA_SHA1]),
489484
digest_algorithms=frozenset([signxml.algorithms.DigestAlgorithm.SHA1]),
490485
),

src/tests/test_data/sii-dte/DTE--76354771-K--33--170--cleaned-mod-replaced-cert.xml

+34-47
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,11 @@
7070
</Reference>
7171
</SignedInfo>
7272
<SignatureValue>
73-
fsYP5p/lNfofAz8POShrJjqXdBTNNtvv4/TWCxbvwTIAXr7BLrlvX3C/Hpfo4viqaxSu1OGFgPnk
74-
ddDIFwj/ZsVdbdB+MhpKkyha83RxhJpYBVBY3c+y9J6oMfdIdMAYXhEkFw8w63KHyhdf2E9dnbKi
75-
wqSxDcYjTT6vXsLPrZk=
73+
wwOMQuFqa6c5gzYSJ5PWfo0OiAf+yNcJK6wx4xJ3VNehlAcMrUB2q+rK/DDhCvjxAoX4NxBACiFD
74+
MrTMIfvxrwXjLd1oX37lSFOtsWX6JxL0SV+tLF7qvWCu1Yzw8ypUf7GDkbymJkoTYDF9JFF8kYU4
75+
FdU2wttiwne9XH8QFHgXsocKP/aygwiOeGqiNX9o/O5XS2GWpt+KM20jrvtYn7UFMED/3aPacCb1
76+
GABizr8mlVEZggZgJunMDChpFQyEigSXMK5I737Ac8D2bw7WB47Wj1WBL3sCFRDlXUXtnMvChBVp
77+
0HRUXYuKHyfpCzqIBXygYrIZexxXgOSnKu/yGg==
7678
</SignatureValue>
7779
<KeyInfo>
7880
<KeyValue>
@@ -87,50 +89,35 @@ Uavs/9J+gR9BBMs/eYE=
8789
</KeyValue>
8890
<X509Data>
8991
<X509Certificate>
90-
MIIIDTCCBvWgAwIBAgIQXD9eCvh/44P1ET5RI1LuJjANBgkqhkiG9w0BAQsFADBU
91-
MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMSUw
92-
IwYDVQQDExxHb29nbGUgSW50ZXJuZXQgQXV0aG9yaXR5IEczMB4XDTE5MDMyNjEz
93-
NDA0MFoXDTE5MDYxODEzMjQwMFowZjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh
94-
bGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzARBgNVBAoMCkdvb2ds
95-
ZSBMTEMxFTATBgNVBAMMDCouZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49
96-
AwEHA0IABANpWSLXLbJm5eRzc1EJmvSIbz0nANT+b11r+XhSUCAbfQhS+4M/91YJ
97-
gVE6UtZJrLO7GGxvp1tV/DL857NaLEWjggWSMIIFjjATBgNVHSUEDDAKBggrBgEF
98-
BQcDATAOBgNVHQ8BAf8EBAMCB4AwggRXBgNVHREEggROMIIESoIMKi5nb29nbGUu
99-
Y29tgg0qLmFuZHJvaWQuY29tghYqLmFwcGVuZ2luZS5nb29nbGUuY29tghIqLmNs
100-
b3VkLmdvb2dsZS5jb22CGCouY3Jvd2Rzb3VyY2UuZ29vZ2xlLmNvbYIGKi5nLmNv
101-
gg4qLmdjcC5ndnQyLmNvbYIKKi5nZ3BodC5jboIWKi5nb29nbGUtYW5hbHl0aWNz
102-
LmNvbYILKi5nb29nbGUuY2GCCyouZ29vZ2xlLmNsgg4qLmdvb2dsZS5jby5pboIO
103-
Ki5nb29nbGUuY28uanCCDiouZ29vZ2xlLmNvLnVrgg8qLmdvb2dsZS5jb20uYXKC
104-
DyouZ29vZ2xlLmNvbS5hdYIPKi5nb29nbGUuY29tLmJygg8qLmdvb2dsZS5jb20u
105-
Y2+CDyouZ29vZ2xlLmNvbS5teIIPKi5nb29nbGUuY29tLnRygg8qLmdvb2dsZS5j
106-
b20udm6CCyouZ29vZ2xlLmRlggsqLmdvb2dsZS5lc4ILKi5nb29nbGUuZnKCCyou
107-
Z29vZ2xlLmh1ggsqLmdvb2dsZS5pdIILKi5nb29nbGUubmyCCyouZ29vZ2xlLnBs
108-
ggsqLmdvb2dsZS5wdIISKi5nb29nbGVhZGFwaXMuY29tgg8qLmdvb2dsZWFwaXMu
109-
Y26CESouZ29vZ2xlY25hcHBzLmNughQqLmdvb2dsZWNvbW1lcmNlLmNvbYIRKi5n
110-
b29nbGV2aWRlby5jb22CDCouZ3N0YXRpYy5jboINKi5nc3RhdGljLmNvbYISKi5n
111-
c3RhdGljY25hcHBzLmNuggoqLmd2dDEuY29tggoqLmd2dDIuY29tghQqLm1ldHJp
112-
Yy5nc3RhdGljLmNvbYIMKi51cmNoaW4uY29tghAqLnVybC5nb29nbGUuY29tghYq
113-
LnlvdXR1YmUtbm9jb29raWUuY29tgg0qLnlvdXR1YmUuY29tghYqLnlvdXR1YmVl
114-
ZHVjYXRpb24uY29tghEqLnlvdXR1YmVraWRzLmNvbYIHKi55dC5iZYILKi55dGlt
115-
Zy5jb22CGmFuZHJvaWQuY2xpZW50cy5nb29nbGUuY29tggthbmRyb2lkLmNvbYIb
116-
ZGV2ZWxvcGVyLmFuZHJvaWQuZ29vZ2xlLmNughxkZXZlbG9wZXJzLmFuZHJvaWQu
117-
Z29vZ2xlLmNuggRnLmNvgghnZ3BodC5jboIGZ29vLmdsghRnb29nbGUtYW5hbHl0
118-
aWNzLmNvbYIKZ29vZ2xlLmNvbYIPZ29vZ2xlY25hcHBzLmNughJnb29nbGVjb21t
119-
ZXJjZS5jb22CGHNvdXJjZS5hbmRyb2lkLmdvb2dsZS5jboIKdXJjaGluLmNvbYIK
120-
d3d3Lmdvby5nbIIIeW91dHUuYmWCC3lvdXR1YmUuY29tghR5b3V0dWJlZWR1Y2F0
121-
aW9uLmNvbYIPeW91dHViZWtpZHMuY29tggV5dC5iZTBoBggrBgEFBQcBAQRcMFow
122-
LQYIKwYBBQUHMAKGIWh0dHA6Ly9wa2kuZ29vZy9nc3IyL0dUU0dJQUczLmNydDAp
123-
BggrBgEFBQcwAYYdaHR0cDovL29jc3AucGtpLmdvb2cvR1RTR0lBRzMwHQYDVR0O
124-
BBYEFM8C2hpNgJL/BEX/yzeB408dhba2MAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgw
125-
FoAUd8K4UJpndnaxLcKG0IOgfqZ+ukswIQYDVR0gBBowGDAMBgorBgEEAdZ5AgUD
126-
MAgGBmeBDAECAjAxBgNVHR8EKjAoMCagJKAihiBodHRwOi8vY3JsLnBraS5nb29n
127-
L0dUU0dJQUczLmNybDANBgkqhkiG9w0BAQsFAAOCAQEAF9PM41ShwCbhtJG7tj2y
128-
ZvF2sHbQ5YuZrMfJc6eeCG+nCKm1U5iJzXnXctFGvfJnUCZpj9YrfwDswdEddWyZ
129-
IG6m6wONF3ZiQifQrcDi0oDA+0BwjEuzYGCGkbfE+Xxb30bVEyDRe51DpJf+cqsb
130-
+DW2pYdikbdrPem5/hwdNerc7nqrQOJ93sqwbVNGktuyJsTOGNKkSwSaejxdN7yl
131-
g5aa4CJsE94gy4+mCywWjnnsjcLGJM3RBUxDdAdTGMldU/r33HCUCXl33Qxc4nvP
132-
MlE9LyFOTIJoajWcpGOsbKWiL3Zr19DKNBSn4Xof0onbtCH7dbpyMwP8XcA2O1dA
133-
ow==
92+
MIIGVDCCBTygAwIBAgIKMUWmvgAAAAjUHTANBgkqhkiG9w0BAQUFADCB0jELMAkGA1UEBhMCQ0wx
93+
HTAbBgNVBAgTFFJlZ2lvbiBNZXRyb3BvbGl0YW5hMREwDwYDVQQHEwhTYW50aWFnbzEUMBIGA1UE
94+
ChMLRS1DRVJUQ0hJTEUxIDAeBgNVBAsTF0F1dG9yaWRhZCBDZXJ0aWZpY2Fkb3JhMTAwLgYDVQQD
95+
EydFLUNFUlRDSElMRSBDQSBGSVJNQSBFTEVDVFJPTklDQSBTSU1QTEUxJzAlBgkqhkiG9w0BCQEW
96+
GHNjbGllbnRlc0BlLWNlcnRjaGlsZS5jbDAeFw0xNzA5MDQyMTExMTJaFw0yMDA5MDMyMTExMTJa
97+
MIHXMQswCQYDVQQGEwJDTDEUMBIGA1UECBMLVkFMUEFSQUlTTyAxETAPBgNVBAcTCFF1aWxsb3Rh
98+
MS8wLQYDVQQKEyZTZXJ2aWNpb3MgQm9uaWxsYSB5IExvcGV6IHkgQ2lhLiBMdGRhLjEkMCIGA1UE
99+
CwwbSW5nZW5pZXLDrWEgeSBDb25zdHJ1Y2Npw7NuMSMwIQYDVQQDExpSYW1vbiBodW1iZXJ0byBM
100+
b3BleiAgSmFyYTEjMCEGCSqGSIb3DQEJARYUZW5hY29ubHRkYUBnbWFpbC5jb20wgZ8wDQYJKoZI
101+
hvcNAQEBBQADgY0AMIGJAoGBAKQeAbNDqfi9M2v86RUGAYgq1ZSDioFC6OLr0SwiOaYnLsSOl+Kx
102+
O394PVwSGa6rZk1ErIZonyi15fU/0nHZLi8iHLB49EB5G3tCwh0s8NfqR9ck0/3Z+TXhVUdiJyJC
103+
/z8x5I5lSUfzNEedJRidVvp6jVGr7P/SfoEfQQTLP3mBAgMBAAGjggKnMIICozA9BgkrBgEEAYI3
104+
FQcEMDAuBiYrBgEEAYI3FQiC3IMvhZOMZoXVnReC4twnge/sPGGBy54UhqiCWAIBZAIBBDAdBgNV
105+
HQ4EFgQU1dVHhF0UVe7RXIz4cjl3/Vew+qowCwYDVR0PBAQDAgTwMB8GA1UdIwQYMBaAFHjhPp/S
106+
ErN6PI3NMA5Ts0MpB7NVMD4GA1UdHwQ3MDUwM6AxoC+GLWh0dHA6Ly9jcmwuZS1jZXJ0Y2hpbGUu
107+
Y2wvZWNlcnRjaGlsZWNhRkVTLmNybDA6BggrBgEFBQcBAQQuMCwwKgYIKwYBBQUHMAGGHmh0dHA6
108+
Ly9vY3NwLmVjZXJ0Y2hpbGUuY2wvb2NzcDAjBgNVHREEHDAaoBgGCCsGAQQBwQEBoAwWCjEzMTg1
109+
MDk1LTYwIwYDVR0SBBwwGqAYBggrBgEEAcEBAqAMFgo5NjkyODE4MC01MIIBTQYDVR0gBIIBRDCC
110+
AUAwggE8BggrBgEEAcNSBTCCAS4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cuZS1jZXJ0Y2hpbGUu
111+
Y2wvQ1BTLmh0bTCB/AYIKwYBBQUHAgIwge8egewAQwBlAHIAdABpAGYAaQBjAGEAZABvACAARgBp
112+
AHIAbQBhACAAUwBpAG0AcABsAGUALgAgAEgAYQAgAHMAaQBkAG8AIAB2AGEAbABpAGQAYQBkAG8A
113+
IABlAG4AIABmAG8AcgBtAGEAIABwAHIAZQBzAGUAbgBjAGkAYQBsACwAIABxAHUAZQBkAGEAbgBk
114+
AG8AIABoAGEAYgBpAGwAaQB0AGEAZABvACAAZQBsACAAQwBlAHIAdABpAGYAaQBjAGEAZABvACAA
115+
cABhAHIAYQAgAHUAcwBvACAAdAByAGkAYgB1AHQAYQByAGkAbzANBgkqhkiG9w0BAQUFAAOCAQEA
116+
mxtPpXWslwI0+uJbyuS9s/S3/Vs0imn758xMU8t4BHUd+OlMdNAMQI1G2+q/OugdLQ/a9Sg3clKD
117+
qXR4lHGl8d/Yq4yoJzDD3Ceez8qenY3JwGUhPzw9oDpg4mXWvxQDXSFeW/u/BgdadhfGnpwx61Un
118+
+/fU24ZgU1dDJ4GKj5oIPHUIjmoSBhnstEhIr6GJWSTcDKTyzRdqBlaVhenH2Qs6Mw6FrOvRPuud
119+
B7lo1+OgxMb/Gjyu6XnEaPu7Vq4XlLYMoCD2xrV7WEADaDTm7KcNLczVAYqWSF1WUqYSxmPoQDFY
120+
+kMTThJyCXBlE0NADInrkwWgLLygkKI7zXkwaw==
134121
</X509Certificate>
135122
</X509Data>
136123
</KeyInfo>

src/tests/test_libs_xml_utils.py

+31-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import lxml.etree
55

6-
from cl_sii.libs.crypto_utils import load_pem_x509_cert
6+
from cl_sii.libs.crypto_utils import _X509CertOpenSsl, load_pem_x509_cert
77
from cl_sii.libs.xml_utils import ( # noqa: F401
88
XmlElement,
99
XmlFeatureForbidden,
@@ -185,6 +185,28 @@ def test_ok_external_trusted_cert(self) -> None:
185185
signature_xml_bytes = f.getvalue()
186186
self.assertEqual(signature_xml_bytes, self.with_valid_signature_signature_xml)
187187

188+
def test_ok_external_trusted_open_ssl_cert_with_signature(self) -> None:
189+
xml_doc = parse_untrusted_xml(self.with_valid_signature)
190+
cert = load_pem_x509_cert(self.xml_doc_cert_pem_bytes)
191+
192+
open_ssl_cert = _X509CertOpenSsl.from_cryptography(cert)
193+
194+
signed_data, signed_xml, signature_xml = verify_xml_signature(
195+
xml_doc, trusted_x509_cert=open_ssl_cert
196+
)
197+
198+
self.assertEqual(signed_data, self.with_valid_signature_signed_data)
199+
200+
f = io.BytesIO()
201+
write_xml_doc(signed_xml, f)
202+
signed_xml_bytes = f.getvalue()
203+
self.assertEqual(signed_xml_bytes, self.with_valid_signature_signed_xml)
204+
205+
f = io.BytesIO()
206+
write_xml_doc(signature_xml, f)
207+
signature_xml_bytes = f.getvalue()
208+
self.assertEqual(signature_xml_bytes, self.with_valid_signature_signature_xml)
209+
188210
def test_ok_cert_in_signature(self) -> None:
189211
# TODO: implement!
190212

@@ -221,7 +243,7 @@ def test_fail_verify_with_other_cert(self) -> None:
221243
verify_xml_signature(xml_doc, trusted_x509_cert=cert)
222244
self.assertEqual(
223245
cm.exception.args,
224-
("Signature verification failed: wrong signature length",),
246+
("Signature verification failed: ",),
225247
)
226248

227249
def test_bad_cert_included(self) -> None:
@@ -244,14 +266,18 @@ def test_bad_cert_included(self) -> None:
244266
)
245267

246268
def test_fail_replaced_cert(self) -> None:
269+
"""
270+
Tests that the signature verification fails
271+
when the certificate is not the one that was used to sign the document.
272+
"""
247273
xml_doc = parse_untrusted_xml(self.with_replaced_cert)
248-
cert = load_pem_x509_cert(self.any_x509_cert_pem_file)
274+
cert = load_pem_x509_cert(self.xml_doc_cert_pem_bytes)
249275

250276
with self.assertRaises(XmlSignatureInvalid) as cm:
251277
verify_xml_signature(xml_doc, trusted_x509_cert=cert)
252278
self.assertEqual(
253279
cm.exception.args,
254-
("Signature verification failed: []",),
280+
("Signature verification failed: ",),
255281
)
256282

257283
def test_fail_included_cert_not_from_a_known_ca(self) -> None:
@@ -262,7 +288,7 @@ def test_fail_included_cert_not_from_a_known_ca(self) -> None:
262288
verify_xml_signature(xml_doc, trusted_x509_cert=None)
263289
self.assertEqual(
264290
cm.exception.args,
265-
('unable to get local issuer certificate',),
291+
('validation failed: cert is not valid at validation time',),
266292
)
267293

268294
def test_fail_signed_data_modified(self) -> None:

0 commit comments

Comments
 (0)