diff --git a/src/zeep/wsse/signature.py b/src/zeep/wsse/signature.py
index c4aec758e..80fff1058 100644
--- a/src/zeep/wsse/signature.py
+++ b/src/zeep/wsse/signature.py
@@ -49,6 +49,7 @@ def __init__(
self,
key_data,
cert_data,
+ cert_public_to_verify_response=None,
password=None,
signature_method=None,
digest_method=None,
@@ -57,6 +58,7 @@ def __init__(
self.key_data = key_data
self.cert_data = cert_data
+ self.cert_public_to_verify_response = cert_public_to_verify_response
self.password = password
self.digest_method = digest_method
self.signature_method = signature_method
@@ -69,8 +71,9 @@ def apply(self, envelope, headers):
return envelope, headers
def verify(self, envelope):
- key = _make_verify_key(self.cert_data)
- _verify_envelope_with_key(envelope, key)
+ if self.cert_public_to_verify_response:
+ key = _make_verify_key(self.cert_public_to_verify_response)
+ _verify_envelope_with_key(envelope, key)
return envelope
@@ -81,13 +84,17 @@ def __init__(
self,
key_file,
certfile,
+ cert_public_to_verify_response=None,
password=None,
signature_method=None,
digest_method=None,
):
+ if cert_public_to_verify_response:
+ cert_public_to_verify_response = _read_file(cert_public_to_verify_response)
super().__init__(
_read_file(key_file),
_read_file(certfile),
+ cert_public_to_verify_response,
password,
signature_method,
digest_method,
diff --git a/tests/public_cert_to_verify_response.crt b/tests/public_cert_to_verify_response.crt
new file mode 100644
index 000000000..41b3cbc88
--- /dev/null
+++ b/tests/public_cert_to_verify_response.crt
@@ -0,0 +1,50 @@
+-----BEGIN CERTIFICATE-----
+MIII+jCCBuKgAwIBAgIDEKTKMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJF
+UzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xOjA4BgNVBAsMMU5aWiBaaXVydGFnaXJp
+IHB1Ymxpa29hIC0gQ2VydGlmaWNhZG8gcHVibGljbyBTQ0kxRjBEBgNVBAMMPUhl
+cnJpdGFyIGV0YSBFcmFrdW5kZWVuIENBIC0gQ0EgZGUgQ2l1ZGFkYW5vcyB5IEVu
+dGlkYWRlcyAoNCkwHhcNMjEwNzEzMDYzOTQ3WhcNMjQwNzEzMDYzOTQ3WjCBvTFJ
+MEcGA1UEAxNASU5GT1JNQVRJS0EgWkVSQklUWlVFTiBGT1JVIEVMS0FSVEVBLVNP
+Q0lFREFEIEZPUkFMIERFIFNFUlZJQ0lPUzELMAkGA1UEBhMCRVMxSTBHBgNVBAoT
+QElORk9STUFUSUtBIFpFUkJJVFpVRU4gRk9SVSBFTEtBUlRFQS1TT0NJRURBRCBG
+T1JBTCBERSBTRVJWSUNJT1MxGDAWBgNVBGETD1ZBVEVTLUEyMDQ1Njk3NjCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIx7C+vnXIIOtInXW1chLNE6A+aJ
+EIh6MHijL0nd2cfkHWpTwHedOJC7432bjw56LUvuFmBBIWOXPN17ZtM6RLT5Vwh9
+JALEgAy9XgW2mq0rcnuz2Y+hHzX5BQ/oTeMoXoJhuqdXHiedmzuUxr+FFGP32Tfd
+G6VtOi7gBIxcskUrRxKZ81basyu+iArkHWrpBo2wFLX8KPnebW58vXe09G90Sy5b
+bpkms4YdpqrZ4ducOrtSciruRfFuzDfdGjRmcj/z91HF5wlcaVHRxzk37uROhCoV
+anuZv8yY1pCrLR2AmFgx1ov6fFWHuNIukXB2CUc8gXNn5ZiFyYvhkfZLJfkCAwEA
+AaOCBBUwggQRMIHHBgNVHRIEgb8wgbyGFWh0dHA6Ly93d3cuaXplbnBlLmNvbYEP
+aW5mb0BpemVucGUuY29tpIGRMIGOMUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJ
+RiBBMDEzMzcyNjAtUk1lcmMuVml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFD
+MEEGA1UECQw6QXZkYSBkZWwgTWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAx
+MDEwIFZpdG9yaWEtR2FzdGVpejAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0lBBYwFAYI
+KwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBTj9KoPA1N0P16WdZmN++ruPdnk
+IDAfBgNVHSMEGDAWgBSkFx1OZdfvh5Uuf464dcsFi9OMfTCCASkGA1UdIASCASAw
+ggEcMIIBDQYJKwYBBAHzOQILMIH/MCUGCCsGAQUFBwIBFhlodHRwOi8vd3d3Lml6
+ZW5wZS5ldXMvY3BzMIHVBggrBgEFBQcCAjCByAyBxUtvbnRzdWx0YSB3d3cuaXpl
+bnBlLmV1cy1lbiBiYWxkaW50emFrIGV0YSBrb25kaXppb2FrIHppdXJ0YWdpcmlh
+biBmaWRhdHUgZWRvIGVyYWJpbGkgYXVycmV0aWsgLSBDb25zdWx0ZSBlbiB3d3cu
+aXplbnBlLmV1cyBsb3MgdMOpcm1pbm9zIHkgY29uZGljaW9uZXMgYW50ZXMgZGUg
+dXRpbGl6YXIgbyBjb25maWFyIGVuIGVsIGNlcnRpZmljYWRvMAkGBwQAi+xAAQEw
+gZ8GCCsGAQUFBwEBBIGSMIGPMCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC5pemVu
+cGUuY29tMGkGCCsGAQUFBzAChl1odHRwOi8vd3d3Lml6ZW5wZS5ldXMvY29udGVu
+aWRvcy9pbmZvcm1hY2lvbi9jYXNfaXplbnBlL2VzX2Nhcy9hZGp1bnRvcy9DQ0VF
+Ul9jZXJ0X3NoYTI1Ni5jcnQwgdEGCCsGAQUFBwEDBIHEMIHBMAgGBgQAjkYBATAL
+BgYEAI5GAQMCAQ8wfAYGBACORgEFMHIwJBYeaHR0cHM6Ly93d3cuaXplbnBlLmV1
+cy9wZHMvZW4vEwJlbjAkFh5odHRwczovL3d3dy5pemVucGUuZXVzL3Bkcy9ldS8T
+AmV1MCQWHmh0dHBzOi8vd3d3Lml6ZW5wZS5ldXMvcGRzL2VzLxMCZXMwEwYGBACO
+RgEGMAkGBwQAjkYBBgIwFQYIKwYBBQUHCwIwCQYHBACL7EkBAjAzBgNVHR8ELDAq
+MCigJqAkhiJodHRwOi8vY3JsLml6ZW5wZS5jb20vY2dpLWJpbi9jcmwyMA0GCSqG
+SIb3DQEBCwUAA4ICAQBzZuzz61om3tQtgxa/X30NQczZ8D4OBp9DBUNX2GBmNhy3
+8zoorr9WHX5pqySjP3PnhX7mk6+IFxvOZy/joSBcGHpyoh02on7Zzao/SV+T8VMZ
+ZpIBsgMuY/oxJ2/L+cY+1q3IQcP5Bxb+7518eGMZ5HDmnaGggT9WtBXA6Qy6iP75
+mohxaq938LLesuVOyBr/oGVMTZSyboz0D2WZkBodRwhzhOcCL64GaVTkHV+sx40j
+LShE+tp8fxh9sXiVdwE3FQHOUAfoH+23cDsI37lQ/ZjbmZVXbP9XR2iQ+c/TQC3v
+dtF1IaSL1pGjbqrV0Hxn+LSuHmSSJBlFLhRgIzctNtDM1Dr3BQ9gRNshgvrOYXWd
++IPMpU6EnlE1eLuwYIvyVgX6AuVMldWS68dIKXBqnfeesQ7L/KU/4htqZKNznb51
+ZGBw/PcpJFjuY4nfNd+YnEvwXSJbjOz+E+jfXfSMxSnHJnm5rblNpft5RceMPsFd
+X5Rt+sOWAWqMGPSeJLdJlaQOz5ThLr3uvSlJrE6LJNF/vp5gYSA08cgrYBh38Ul9
+ocKCJt7hrR64tBgX242pA3F8bD4Hory8IzWojqJAH0wnf0xCJwFJMyl0OI/WakJP
+ZfFGhGgNLyfsAbLEZX7Lo9oXYmBVnjN3j7Q4G5NOvsiFcgW7gMdnzg/Rjt1d7Q==
+-----END CERTIFICATE-----
diff --git a/tests/responses_examples/response_signed.xml b/tests/responses_examples/response_signed.xml
new file mode 100644
index 000000000..992081298
--- /dev/null
+++ b/tests/responses_examples/response_signed.xml
@@ -0,0 +1,37 @@
+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
+
+
+
+
+
+
+
+
+bQM8HrMFPhywqYuqXMAZSaYvQIM=
+
+
+
+
+
+
+pelvAc4x6QHNNe98pdEELilM7js=
+
+
+
+
+
+
+ZC3VPHde8wrvgOfI7ZU4T28fhz8=
+
+
+
+VLg1gujs/OX7cIFqydTg4cobj5ESCULxLR6VmanHGzarWDg9M7xvCPrBOrVSG0cbGQof+r80E2MK
+4FkrXg+0s1uIo1WDOB+OVQVtakd17LlEssn2ip0oyEZrCSfCCKKIxrNhTCmyDzAFIh9Ibn06+Fo3
+wLg30N3IIa5vVsZ/p1QWkjpNpZHM35kMymfRmrIeo0ADfKJIgfqz11MRq49qLXpwX9pFsPHX/Q/s
+HJzvFw1PMlX89rPpuuCTdyZ08HXF68HtdLJHuwWGSmnr3aKK3KO/uE9IOs/4qmmvIq3Y0/AzYwl+
+boyI9xeHL4//sZNe1/uWg7EKn1b8LvWvJQ8Atw==
+
+
+
+
+2022-11-08T14:40:48.040Z2022-11-08T14:41:47.040Z0Correcto/Zuzena2022-0005660481200Erregistratua / Registrada4100Ezeztapena ez da eskatu / No solicita anulación
\ No newline at end of file
diff --git a/tests/test_wsse_verify_response.py b/tests/test_wsse_verify_response.py
new file mode 100644
index 000000000..9205975a3
--- /dev/null
+++ b/tests/test_wsse_verify_response.py
@@ -0,0 +1,39 @@
+import os
+import sys
+
+import pytest
+import zeep
+from zeep.wsse.signature import xmlsec as xmlsec_installed
+import requests_mock
+from zeep.wsse.signature import Signature
+from zeep import helpers
+
+
+KEY_FILE = os.path.join(os.path.dirname(os.path.realpath(__file__)), "cert_valid.pem")
+PUBLIC_CERT_TO_VERIFY_RESP = os.path.join(os.path.dirname(os.path.realpath(__file__)), "public_cert_to_verify_response.crt")
+WSDL_FILE = os.path.join(os.path.dirname(os.path.realpath(__file__)), "wsdl_files/wsdl_to_verify_response.wsdl")
+RESPONSE_XML = os.path.join(os.path.dirname(os.path.realpath(__file__)), "responses_examples/response_signed.xml")
+
+skip_if_no_xmlsec = pytest.mark.skipif(
+ sys.platform == "win32", reason="does not run on windows"
+) and pytest.mark.skipif(
+ xmlsec_installed is None, reason="xmlsec library not installed"
+)
+
+
+@skip_if_no_xmlsec
+def test_wsse_verify_response():
+ """
+ 1 - We assume that the answer from any server from any company is signed.
+ 2 - We have a public certificate of any company to verify signed responses.
+ """
+ sig = Signature(key_file=KEY_FILE, certfile=KEY_FILE, cert_public_to_verify_response=PUBLIC_CERT_TO_VERIFY_RESP)
+ client = zeep.Client(wsdl=WSDL_FILE, wsse=sig)
+ response_ = open(RESPONSE_XML, "r")
+ response = response_.read()
+ with requests_mock.mock() as m:
+ m.post('https://webservice.face.gob.es', text=response, status_code=200)
+ result = client.service.consultarFactura('2022-000566048')
+ resp_exp = {"resultado": {"codigo": "0", "descripcion": "Correcto/Zuzena", "codigoSeguimiento": None}, "factura": {"numeroRegistro": "2022-000566048", "tramitacion": {"codigo": "1200", "descripcion": "Erregistratua / Registrada", "motivo": None}, "anulacion": {"codigo": "4100", "descripcion": "Ezeztapena ez da eskatu / No solicita anulación", "motivo": None}}}
+ resp = helpers.serialize_object(result, dict)
+ assert resp_exp == resp
\ No newline at end of file
diff --git a/tests/wsdl_files/wsdl_to_verify_response.wsdl b/tests/wsdl_files/wsdl_to_verify_response.wsdl
new file mode 100644
index 000000000..741e90718
--- /dev/null
+++ b/tests/wsdl_files/wsdl_to_verify_response.wsdl
@@ -0,0 +1,688 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file