diff options
author | Ivan Kanakarakis <ivan.kanak@gmail.com> | 2021-01-09 00:31:13 +0200 |
---|---|---|
committer | Ivan Kanakarakis <ivan.kanak@gmail.com> | 2021-01-15 16:09:06 +0200 |
commit | 3b707723dcf1bf60677b424aac398c0c3557641d (patch) | |
tree | 32be8bf3732a60e3f0697ba9d024cac6d6929374 /tests/test_xsw.py | |
parent | b76ea403e3107bbae73b653215985b9e1f27c5d4 (diff) | |
download | pysaml2-3b707723dcf1bf60677b424aac398c0c3557641d.tar.gz |
Fix CVE-2021-21238 - SAML XML Signature wrapping
All users of pysaml2 that use the default `CryptoBackendXmlSec1` backend and need to
verify signed SAML documents are impacted. `pysaml2 <= 6.4.1` does not validate the SAML
document against an XML schema. This allows invalid XML documents to trick the
verification process, by presenting elements with a valid signature inside elements
whose content has been malformed. The verification is offloaded to `xmlsec1` and
`xmlsec1` will not validate every signature in the given document, but only the first it
finds in the given scope.
Credits for the report:
- Victor Schönfelder Garcia (isits AG International School of IT Security)
- Juraj Somorovsky (Paderborn University)
- Vladislav Mladenov (Ruhr University Bochum)
Signed-off-by: Ivan Kanakarakis <ivan.kanak@gmail.com>
Diffstat (limited to 'tests/test_xsw.py')
-rw-r--r-- | tests/test_xsw.py | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/tests/test_xsw.py b/tests/test_xsw.py index cb756f76..0e92a5bd 100644 --- a/tests/test_xsw.py +++ b/tests/test_xsw.py @@ -18,6 +18,8 @@ SIGNED_XSW_ASSERTION_WRAPPER = full_path("xsw/signed-xsw-assertion-wrapper.xml") SIGNED_XSW_ASSERTION_EXTENSIONS = full_path("xsw/signed-xsw-assertion-extensions.xml") SIGNED_XSW_ASSERTION_ASSERTION = full_path("xsw/signed-xsw-assertion-assertion.xml") +SIGNED_ASSERTION_FIRST_SIG = full_path("xsw/signed-xsw-assertion-in-assertion-first-sig.xml") +SIGNED_REPONSE_FIRST_SIG = full_path("xsw/signed-xsw-response-in-response-first-sig.xml") class TestXSW: @@ -87,3 +89,42 @@ class TestXSW: assert self.ar.ava is None assert self.ar.name_id is None + + +class TestInvalidDepthFirstSig: + def setup_class(self): + self.conf = config_factory("sp", dotname("server_conf")) + self.ar = authn_response(self.conf, return_addrs="https://example.org/acs/post") + + @patch('saml2.response.validate_on_or_after', return_value=True) + def test_signed_assertion_first_sig_should_fail(self, mock_validate_on_or_after): + self.ar.issue_instant_ok = Mock(return_value=True) + + with open(SIGNED_ASSERTION_FIRST_SIG) as fp: + xml_response = fp.read() + + self.ar.outstanding_queries = {"id-abc": "http://localhost:8088/sso"} + self.ar.timeslack = 10000 + self.ar.loads(xml_response, decode=False) + + assert self.ar.came_from == 'http://localhost:8088/sso' + assert self.ar.session_id() == "id-abc" + assert self.ar.issuer() == 'urn:mace:example.com:saml:roland:idp' + + with raises(SignatureError): + self.ar.verify() + + assert self.ar.ava is None + assert self.ar.name_id is None + + @patch('saml2.response.validate_on_or_after', return_value=True) + def test_signed_response_first_sig_should_fail(self, mock_validate_on_or_after): + self.ar.issue_instant_ok = Mock(return_value=True) + + with open(SIGNED_REPONSE_FIRST_SIG) as fp: + xml_response = fp.read() + + self.ar.outstanding_queries = {"id-abc": "http://localhost:8088/sso"} + self.ar.timeslack = 10000 + with raises(SignatureError): + self.ar.loads(xml_response, decode=False) |