Skip to content

feat: validate responses encrypted with XML Encryption 1.1 - #13

Merged
marevol merged 1 commit into
mainfrom
feat/xml-encryption-11-schema
Aug 17, 2026
Merged

feat: validate responses encrypted with XML Encryption 1.1#13
marevol merged 1 commit into
mainfrom
feat/xml-encryption-11-schema

Conversation

@marevol

@marevol marevol commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Found while verifying Fess 15.8's SAML SSO against a real IdP. Intended for the
release Fess 15.9 picks up, not for 15.8.

The problem

A service provider that asks for encrypted assertions cannot accept them from an
IdP that encrypts with XML Encryption 1.1. Current Keycloak does exactly that by
default: http://www.w3.org/2009/xmlenc11#rsa-oaep for key transport (with an
<xenc11:MGF> child naming mgf1sha256) and xmlenc11#aes256-gcm for content.

<xenc:EncryptionMethod> ends in <any namespace="##other"> whose
processContents is strict, so anything carried there must be declared in the
schema set. The set built here covers XML Encryption 1.0 only, so validation fails:

Errors found when validating SAML response with schema: [org.xml.sax.SAXParseException;
cvc-complex-type.2.4.c: ... no declaration found for element 'xenc11:MGF']
Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd

The response is refused in full, before decryption is attempted. Nothing about
it is malformed — the keys, certificate and ciphertext are all correct, and the same
response logs the user in once wantXMLValidation is turned off. The message points
at a malformed document rather than at an algorithm the schema set does not know, so
there is no path from the log to the cause.

The change

  • Bundles the W3C XML Encryption 1.1 schema alongside the ones already shipped
    (xenc-schema.xsd, xmldsig-core-schema.xsd, …). It carries the same W3C
    copyright header as its siblings and imports only xmldsig-core and XML Encryption
    1.0, both of which are already present.
  • Compiles it into every schema set loadFromUrl builds, by passing both sources to
    newSchema. Editing a published schema to add an <import> would work too, but
    keeping the OASIS and W3C files byte-identical to what they publish seems worth
    more than the one-line diff.
  • Maps the 1.1 namespace to the local copy in the resolver, so a document that
    imports it is never fetched over the network — the same treatment every other
    namespace here gets.

Tests

core 415 → 416, toolkit 92, all green.

The new test uses a response whose EncryptedKey carries the <xenc11:MGF> element
an IdP actually emits. A test that only asserted "this now validates" would pass just
as well if validation had been loosened, so it also asserts that
<xenc11:NoSuchElement> — an element that does not exist in the 1.1 namespace — is
still refused. Against the previous SchemaFactory the test fails on the response it
is named for.

What was measured, and what was not

Measured against a real IdP: an encrypted assertion refused with exactly the error
above while schema validation was on, and the same configuration logging in
successfully with it off — so decryption of RSA-OAEP/MGF1-SHA256 and AES-256-GCM
already works and schema validation was the only blocker. This PR is what removes
that blocker; the end-to-end run has not been repeated on top of this branch.

An IdP that encrypts with XML Encryption 1.1 puts an <xenc11:MGF> element
inside <xenc:EncryptionMethod>. That position is a wildcard whose
processContents is strict, so the element has to be declared somewhere in the
schema set; the set here carried XML Encryption 1.0 only. The result was that
the entire response failed schema validation -- before decryption was even
attempted -- with:

    cvc-complex-type.2.4.c: ... no declaration found for element 'xenc11:MGF'
    Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd

Nothing is wrong with such a message: the keys, the certificate and the
ciphertext are all fine, and the same response is accepted and decrypted once
schema validation is switched off. Current Keycloak encrypts this way by
default (xmlenc11#rsa-oaep with mgf1sha256, xmlenc11#aes256-gcm), so a service
provider asking for encrypted assertions could not accept its assertions at
all.

Adds the W3C XML Encryption 1.1 schema next to the ones already bundled and
compiles it into every schema set built here, rather than editing a published
schema to import it. The resolver also maps the 1.1 namespace to the local
copy, so a document that imports it is never fetched over the network.

The added test would pass just as well if validation had been loosened, so it
also asserts that an element that does not exist in the 1.1 namespace is still
refused. Without the schema the test fails on the response it is named for.
@marevol
marevol merged commit 967ad54 into main Aug 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant