diff --git a/composer.json b/composer.json
index f891a767..bf372b1a 100644
--- a/composer.json
+++ b/composer.json
@@ -43,8 +43,8 @@
"ext-pcre": "*",
"ext-spl": "*",
- "simplesamlphp/assert": "^1.5",
- "simplesamlphp/xml-common": "^1.20.0"
+ "simplesamlphp/assert": "^1.6",
+ "simplesamlphp/xml-common": "^1.21.0"
},
"require-dev": {
"simplesamlphp/simplesamlphp-test-framework": "^1.7"
diff --git a/resources/schemas/xenc-schema-11.xsd b/resources/schemas/xenc-schema-11.xsd
new file mode 100644
index 00000000..b7702c6b
--- /dev/null
+++ b/resources/schemas/xenc-schema-11.xsd
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Constants.php b/src/Constants.php
index 7b39c159..402d43e5 100644
--- a/src/Constants.php
+++ b/src/Constants.php
@@ -148,6 +148,7 @@ class Constants extends \SimpleSAML\XML\Constants
public const XMLDSIG_MANIFEST = 'http://www.w3.org/2000/09/xmldsig#Manifest';
public const NS_XENC = 'http://www.w3.org/2001/04/xmlenc#';
+ public const NS_XENC11 = 'http://www.w3.org/2009/xmlenc11#';
public const XMLENC_CONTENT = 'http://www.w3.org/2001/04/xmlenc#Content';
public const XMLENC_ELEMENT = 'http://www.w3.org/2001/04/xmlenc#Element';
public const XMLENC_ENCRYPTEDKEY = 'http://www.w3.org/2001/04/xmlenc#EncryptedKey';
diff --git a/src/XML/xenc11/AbstractAlgorithmIdentifierType.php b/src/XML/xenc11/AbstractAlgorithmIdentifierType.php
new file mode 100644
index 00000000..64cda62c
--- /dev/null
+++ b/src/XML/xenc11/AbstractAlgorithmIdentifierType.php
@@ -0,0 +1,70 @@
+.
+ *
+ * @package simplesamlphp/xml-security
+ */
+abstract class AbstractAlgorithmIdentifierType extends AbstractXenc11Element
+{
+ /**
+ * AlgorithmIdentifierType constructor.
+ *
+ * @param string $Algorithm
+ * @param \SimpleSAML\XMLSecurity\XML\xenc11\Parameters|null $parameters
+ */
+ public function __construct(
+ protected string $Algorithm,
+ protected ?Parameters $parameters = null,
+ ) {
+ Assert::validURI($Algorithm, SchemaViolationException::class);
+ }
+
+
+ /**
+ * Get the value of the $Algorithm property.
+ *
+ * @return string
+ */
+ public function getAlgorithm(): string
+ {
+ return $this->Algorithm;
+ }
+
+
+ /**
+ * Get the value of the $parameters property.
+ *
+ * @return \SimpleSAML\XMLSecurity\XML\xenc11\Parameters|null
+ */
+ public function getParameters(): ?Parameters
+ {
+ return $this->parameters;
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public function toXML(?DOMElement $parent = null): DOMElement
+ {
+ $e = $this->instantiateParentElement($parent);
+ $e->setAttribute('Algorithm', $this->getAlgorithm());
+
+ if ($this->getParameters() !== null) {
+ if (!$this->getParameters()->isEmptyElement()) {
+ $this->getParameters()->toXML($e);
+ }
+ }
+
+ return $e;
+ }
+}
diff --git a/src/XML/xenc11/AbstractConcatKDFParamsType.php b/src/XML/xenc11/AbstractConcatKDFParamsType.php
new file mode 100644
index 00000000..f916d180
--- /dev/null
+++ b/src/XML/xenc11/AbstractConcatKDFParamsType.php
@@ -0,0 +1,173 @@
+.
+ *
+ * @package simplesamlphp/xml-security
+ */
+abstract class AbstractConcatKDFParamsType extends AbstractXenc11Element
+{
+ /**
+ * ConcatKDFParams constructor.
+ *
+ * @param \SimpleSAML\XMLSecurity\XML\ds\DigestMethod $digestMethod
+ * @param string|null $AlgorithmID
+ * @param string|null $PartyUInfo
+ * @param string|null $PartyVInfo
+ * @param string|null $SuppPubInfo
+ * @param string|null $SuppPrivInfo
+ */
+ final public function __construct(
+ protected DigestMethod $digestMethod,
+ protected ?string $AlgorithmID = null,
+ protected ?string $PartyUInfo = null,
+ protected ?string $PartyVInfo = null,
+ protected ?string $SuppPubInfo = null,
+ protected ?string $SuppPrivInfo = null,
+ ) {
+ Assert::validHexBinary($AlgorithmID, SchemaViolationException::class);
+ Assert::validHexBinary($PartyUInfo, SchemaViolationException::class);
+ Assert::validHexBinary($PartyVInfo, SchemaViolationException::class);
+ Assert::validHexBinary($SuppPubInfo, SchemaViolationException::class);
+ Assert::validHexBinary($SuppPrivInfo, SchemaViolationException::class);
+ }
+
+
+ /**
+ * Get the value of the $digestMethod property.
+ *
+ * @return \SimpleSAML\XMLSecurity\XML\ds\DigestMethod
+ */
+ public function getDigestMethod(): DigestMethod
+ {
+ return $this->digestMethod;
+ }
+
+
+ /**
+ * Get the value of the $AlgorithmID property.
+ *
+ * @return string|null
+ */
+ public function getAlgorithmID(): ?string
+ {
+ return $this->AlgorithmID;
+ }
+
+
+ /**
+ * Get the value of the $PartyUInfo property.
+ *
+ * @return string|null
+ */
+ public function getPartyUInfo(): ?string
+ {
+ return $this->PartyUInfo;
+ }
+
+
+ /**
+ * Get the value of the $PartyVInfo property.
+ *
+ * @return string|null
+ */
+ public function getPartyVInfo(): ?string
+ {
+ return $this->PartyVInfo;
+ }
+
+
+ /**
+ * Get the value of the $SuppPubInfo property.
+ *
+ * @return string|null
+ */
+ public function getSuppPubInfo(): ?string
+ {
+ return $this->SuppPubInfo;
+ }
+
+
+ /**
+ * Get the value of the $SuppPrivInfo property.
+ *
+ * @return string|null
+ */
+ public function getSuppPrivInfo(): ?string
+ {
+ return $this->SuppPrivInfo;
+ }
+
+
+ /**
+ * @inheritDoc
+ *
+ * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
+ * If the qualified name of the supplied element is wrong
+ */
+ public static function fromXML(DOMElement $xml): static
+ {
+ Assert::same($xml->localName, static::getLocalName(), InvalidDOMElementException::class);
+ Assert::same($xml->namespaceURI, static::getNamespaceURI(), InvalidDOMElementException::class);
+
+ $digestMethod = DigestMethod::getChildrenOfClass($xml);
+ Assert::minCount($digestMethod, 1, MissingElementException::class);
+ Assert::maxCount($digestMethod, 1, TooManyElementsException::class);
+
+ return new static(
+ array_pop($digestMethod),
+ self::getOptionalAttribute($xml, 'AlgorithmID', null),
+ self::getOptionalAttribute($xml, 'PartyUInfo', null),
+ self::getOptionalAttribute($xml, 'PartyVInfo', null),
+ self::getOptionalAttribute($xml, 'SuppPubInfo', null),
+ self::getOptionalAttribute($xml, 'SuppPrivInfo', null),
+ );
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public function toXML(?DOMElement $parent = null): DOMElement
+ {
+ $e = $this->instantiateParentElement($parent);
+
+ if ($this->getAlgorithmID() !== null) {
+ $e->setAttribute('AlgorithmID', $this->getAlgorithmID());
+ }
+
+ if ($this->getPartyUInfo() !== null) {
+ $e->setAttribute('PartyUInfo', $this->getPartyUInfo());
+ }
+
+ if ($this->getPartyVInfo() !== null) {
+ $e->setAttribute('PartyVInfo', $this->getPartyVInfo());
+ }
+
+ if ($this->getSuppPubInfo() !== null) {
+ $e->setAttribute('SuppPubInfo', $this->getSuppPubInfo());
+ }
+
+ if ($this->getSuppPrivInfo() !== null) {
+ $e->setAttribute('SuppPrivInfo', $this->getSuppPrivInfo());
+ }
+
+ $this->getDigestMethod()->toXML($e);
+
+ return $e;
+ }
+}
diff --git a/src/XML/xenc11/AbstractDerivedKeyType.php b/src/XML/xenc11/AbstractDerivedKeyType.php
new file mode 100644
index 00000000..4531265a
--- /dev/null
+++ b/src/XML/xenc11/AbstractDerivedKeyType.php
@@ -0,0 +1,203 @@
+.
+ *
+ * @package simplesamlphp/xml-security
+ */
+abstract class AbstractDerivedKeyType extends AbstractXenc11Element
+{
+ /**
+ * DerivedKey constructor.
+ *
+ * @param string|null $recipient
+ * @param string|null $id
+ * @param string|null $type
+ * @param \SimpleSAML\XMLSecurity\XML\xenc11\KeyDerivationMethod|null $keyDerivationMethod
+ * @param \SimpleSAML\XMLSecurity\XML\xenc\ReferenceList|null $referenceList
+ * @param \SimpleSAML\XMLSecurity\XML\xenc11\DerivedKeyName|null $derivedKeyName
+ * @param \SimpleSAML\XMLSecurity\XML\xenc11\MasterKeyName|null $masterKeyName
+ */
+ final public function __construct(
+ protected ?string $recipient = null,
+ protected ?string $id = null,
+ protected ?string $type = null,
+ protected ?KeyDerivationMethod $keyDerivationMethod = null,
+ protected ?ReferenceList $referenceList = null,
+ protected ?DerivedKeyName $derivedKeyName = null,
+ protected ?MasterKeyName $masterKeyName = null,
+ ) {
+ Assert::nullOrValidNCName($id, SchemaViolationException::class);
+ Assert::nullOrValidURI($type, SchemaViolationException::class);
+ }
+
+
+ /**
+ * Get the value of the $recipient property.
+ *
+ * @return string|null
+ */
+ public function getRecipient(): ?string
+ {
+ return $this->recipient;
+ }
+
+
+ /**
+ * Get the value of the $id property.
+ *
+ * @return string|null
+ */
+ public function getId(): ?string
+ {
+ return $this->id;
+ }
+
+
+ /**
+ * Get the value of the $type property.
+ *
+ * @return string|null
+ */
+ public function getType(): ?string
+ {
+ return $this->type;
+ }
+
+
+ /**
+ * Get the value of the $keyDerivationMethod property.
+ *
+ * @return \SimpleSAML\XMLSecurity\XML\xenc11\KeyDerivationMethod|null
+ */
+ public function getKeyDerivationMethod(): ?KeyDerivationMethod
+ {
+ return $this->keyDerivationMethod;
+ }
+
+
+ /**
+ * Get the value of the $referenceList property.
+ *
+ * @return \SimpleSAML\XMLSecurity\XML\xenc\ReferenceList|null
+ */
+ public function getReferenceList(): ?ReferenceList
+ {
+ return $this->referenceList;
+ }
+
+
+ /**
+ * Get the value of the $derivedKeyName property.
+ *
+ * @return \SimpleSAML\XMLSecurity\XML\xenc11\DerivedKeyName|null
+ */
+ public function getDerivedKeyName(): ?DerivedKeyName
+ {
+ return $this->derivedKeyName;
+ }
+
+
+ /**
+ * Get the value of the $masterKeyName property.
+ *
+ * @return \SimpleSAML\XMLSecurity\XML\xenc11\MasterKeyName|null
+ */
+ public function getMasterKeyName(): ?MasterKeyName
+ {
+ return $this->masterKeyName;
+ }
+
+
+ /**
+ * Test if an object, at the state it's in, would produce an empty XML-element
+ *
+ * @return bool
+ */
+ public function isEmptyElement(): bool
+ {
+ return empty($this->getKeyDerivationMethod())
+ && empty($this->getReferenceList())
+ && empty($this->getDerivedKeyName())
+ && empty($this->getMasterKeyName())
+ && empty($this->getRecipient())
+ && empty($this->getId())
+ && empty($this->getType());
+ }
+
+
+ /**
+ * @inheritDoc
+ *
+ * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
+ * If the qualified name of the supplied element is wrong
+ */
+ public static function fromXML(DOMElement $xml): static
+ {
+ Assert::same($xml->localName, static::getLocalName(), InvalidDOMElementException::class);
+ Assert::same($xml->namespaceURI, static::getNamespaceURI(), InvalidDOMElementException::class);
+
+ $keyDerivationMethod = KeyDerivationMethod::getChildrenOfClass($xml);
+ Assert::maxCount($keyDerivationMethod, 1, TooManyElementsException::class);
+
+ $referenceList = ReferenceList::getChildrenOfClass($xml);
+ Assert::maxCount($referenceList, 1, TooManyElementsException::class);
+
+ $derivedKeyName = DerivedKeyName::getChildrenOfClass($xml);
+ Assert::maxCount($derivedKeyName, 1, TooManyElementsException::class);
+
+ $masterKeyName = MasterKeyName::getChildrenOfClass($xml);
+ Assert::maxCount($masterKeyName, 1, TooManyElementsException::class);
+
+ return new static(
+ self::getOptionalAttribute($xml, 'Recipient', null),
+ self::getOptionalAttribute($xml, 'Id', null),
+ self::getOptionalAttribute($xml, 'Type', null),
+ array_pop($keyDerivationMethod),
+ array_pop($referenceList),
+ array_pop($derivedKeyName),
+ array_pop($masterKeyName),
+ );
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public function toXML(?DOMElement $parent = null): DOMElement
+ {
+ $e = $this->instantiateParentElement($parent);
+
+ if ($this->getRecipient() !== null) {
+ $e->setAttribute('Recipient', $this->getRecipient());
+ }
+
+ if ($this->getId() !== null) {
+ $e->setAttribute('Id', $this->getId());
+ }
+
+ if ($this->getType() !== null) {
+ $e->setAttribute('Type', $this->getType());
+ }
+
+ $this->getKeyDerivationMethod()?->toXML($e);
+ $this->getReferenceList()?->toXML($e);
+ $this->getDerivedKeyName()?->toXML($e);
+ $this->getMasterKeyName()?->toXML($e);
+
+ return $e;
+ }
+}
diff --git a/src/XML/xenc11/AbstractKeyDerivationMethodType.php b/src/XML/xenc11/AbstractKeyDerivationMethodType.php
new file mode 100644
index 00000000..d6096817
--- /dev/null
+++ b/src/XML/xenc11/AbstractKeyDerivationMethodType.php
@@ -0,0 +1,88 @@
+.
+ *
+ * @package simplesamlphp/xml-security
+ */
+abstract class AbstractKeyDerivationMethodType extends AbstractXenc11Element
+{
+ use ExtendableElementTrait;
+
+ /** The namespace-attribute for the xs:any element */
+ public const XS_ANY_ELT_NAMESPACE = NS::ANY;
+
+
+ /**
+ * KeyDerivationMethod constructor.
+ *
+ * @param string $Algorithm
+ * @param \SimpleSAML\XML\SerializableElementInterface[] $children
+ */
+ final public function __construct(
+ protected string $Algorithm,
+ array $children,
+ ) {
+ Assert::validURI($Algorithm, SchemaViolationException::class);
+
+ $this->setElements($children);
+ }
+
+
+ /**
+ * Get the value of the $Algorithm property.
+ *
+ * @return string
+ */
+ public function getAlgorithm(): string
+ {
+ return $this->Algorithm;
+ }
+
+
+ /**
+ * @inheritDoc
+ *
+ * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
+ * If the qualified name of the supplied element is wrong
+ */
+ public static function fromXML(DOMElement $xml): static
+ {
+ Assert::same($xml->localName, static::getLocalName(), InvalidDOMElementException::class);
+ Assert::same($xml->namespaceURI, static::getNamespaceURI(), InvalidDOMElementException::class);
+
+ return new static(
+ self::getOptionalAttribute($xml, 'Algorithm', null),
+ self::getChildElementsFromXML($xml),
+ );
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public function toXML(?DOMElement $parent = null): DOMElement
+ {
+ $e = $this->instantiateParentElement($parent);
+ $e->setAttribute('Algorithm', $this->getAlgorithm());
+
+ foreach ($this->getElements() as $child) {
+ if (!$child->isEmptyElement()) {
+ $child->toXML($e);
+ }
+ }
+
+ return $e;
+ }
+}
diff --git a/src/XML/xenc11/AbstractMGFType.php b/src/XML/xenc11/AbstractMGFType.php
new file mode 100644
index 00000000..fafd6e27
--- /dev/null
+++ b/src/XML/xenc11/AbstractMGFType.php
@@ -0,0 +1,24 @@
+.
+ *
+ * @package simplesamlphp/xml-security
+ */
+abstract class AbstractMGFType extends AbstractAlgorithmIdentifierType
+{
+ /**
+ * MGFType constructor.
+ *
+ * @param string $Algorithm
+ */
+ public function __construct(
+ string $Algorithm,
+ ) {
+ parent::__construct($Algorithm, null);
+ }
+}
diff --git a/src/XML/xenc11/AbstractPBKDF2ParameterType.php b/src/XML/xenc11/AbstractPBKDF2ParameterType.php
new file mode 100644
index 00000000..69465d8b
--- /dev/null
+++ b/src/XML/xenc11/AbstractPBKDF2ParameterType.php
@@ -0,0 +1,133 @@
+.
+ *
+ * @package simplesamlphp/xml-security
+ */
+abstract class AbstractPBKDF2ParameterType extends AbstractXenc11Element
+{
+ /**
+ * PBKDF2ParameterType constructor.
+ *
+ * @param \SimpleSAML\XMLSecurity\XML\xenc11\Salt $salt
+ * @param \SimpleSAML\XMLSecurity\XML\xenc11\IterationCount $iterationCount
+ * @param \SimpleSAML\XMLSecurity\XML\xenc11\KeyLength $keyLength
+ * @param \SimpleSAML\XMLSecurity\XML\xenc11\PRF $prf
+ */
+ final public function __construct(
+ protected Salt $salt,
+ protected IterationCount $iterationCount,
+ protected KeyLength $keyLength,
+ protected PRF $prf,
+ ) {
+ }
+
+
+ /**
+ * Get the value of the $salt property.
+ *
+ * @return \SimpleSAML\XMLSecurity\XML\xenc11\Salt
+ */
+ public function getSalt(): Salt
+ {
+ return $this->salt;
+ }
+
+
+ /**
+ * Get the value of the $iterationCount property.
+ *
+ * @return \SimpleSAML\XMLSecurity\XML\xenc11\IterationCount
+ */
+ public function getIterationCount(): IterationCount
+ {
+ return $this->iterationCount;
+ }
+
+
+ /**
+ * Get the value of the $keyLength property.
+ *
+ * @return \SimpleSAML\XMLSecurity\XML\xenc11\KeyLength
+ */
+ public function getKeyLength(): KeyLength
+ {
+ return $this->keyLength;
+ }
+
+
+ /**
+ * Get the value of the $prf property.
+ *
+ * @return \SimpleSAML\XMLSecurity\XML\xenc11\PRF
+ */
+ public function getPRF(): PRF
+ {
+ return $this->prf;
+ }
+
+
+ /**
+ * @inheritDoc
+ *
+ * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
+ * If the qualified name of the supplied element is wrong
+ */
+ public static function fromXML(DOMElement $xml): static
+ {
+ Assert::same($xml->localName, static::getLocalName(), InvalidDOMElementException::class);
+ Assert::same($xml->namespaceURI, static::getNamespaceURI(), InvalidDOMElementException::class);
+
+ $salt = Salt::getChildrenOfClass($xml);
+ Assert::minCount($salt, 1, MissingElementException::class);
+ Assert::maxCount($salt, 1, TooManyElementsException::class);
+
+ $iterationCount = IterationCount::getChildrenOfClass($xml);
+ Assert::minCount($iterationCount, 1, MissingElementException::class);
+ Assert::maxCount($iterationCount, 1, TooManyElementsException::class);
+
+ $keyLength = KeyLength::getChildrenOfClass($xml);
+ Assert::minCount($keyLength, 1, MissingElementException::class);
+ Assert::maxCount($keyLength, 1, TooManyElementsException::class);
+
+ $prf = PRF::getChildrenOfClass($xml);
+ Assert::minCount($prf, 1, MissingElementException::class);
+ Assert::maxCount($prf, 1, TooManyElementsException::class);
+
+ return new static(
+ array_pop($salt),
+ array_pop($iterationCount),
+ array_pop($keyLength),
+ array_pop($prf),
+ );
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public function toXML(?DOMElement $parent = null): DOMElement
+ {
+ $e = $this->instantiateParentElement($parent);
+
+ $this->getSalt()->toXML($e);
+ $this->getIterationCount()->toXML($e);
+ $this->getKeyLength()->toXML($e);
+ $this->getPRF()->toXML($e);
+
+ return $e;
+ }
+}
diff --git a/src/XML/xenc11/AbstractPRFAlgorithmIdentifierType.php b/src/XML/xenc11/AbstractPRFAlgorithmIdentifierType.php
new file mode 100644
index 00000000..a3f73576
--- /dev/null
+++ b/src/XML/xenc11/AbstractPRFAlgorithmIdentifierType.php
@@ -0,0 +1,24 @@
+.
+ *
+ * @package simplesamlphp/xml-security
+ */
+abstract class AbstractPRFAlgorithmIdentifierType extends AbstractAlgorithmIdentifierType
+{
+ /**
+ * AlgorithmPRFIdentifierType constructor.
+ *
+ * @param string $Algorithm
+ */
+ public function __construct(
+ string $Algorithm,
+ ) {
+ parent::__construct($Algorithm, null);
+ }
+}
diff --git a/src/XML/xenc11/AbstractXenc11Element.php b/src/XML/xenc11/AbstractXenc11Element.php
new file mode 100644
index 00000000..dfc979c0
--- /dev/null
+++ b/src/XML/xenc11/AbstractXenc11Element.php
@@ -0,0 +1,22 @@
+setContent($content);
+ }
+}
diff --git a/src/XML/xenc11/IterationCount.php b/src/XML/xenc11/IterationCount.php
new file mode 100644
index 00000000..f57fa2a3
--- /dev/null
+++ b/src/XML/xenc11/IterationCount.php
@@ -0,0 +1,73 @@
+iterationCount;
+ }
+
+
+ /**
+ * Convert XML into a class instance
+ *
+ * @param \DOMElement $xml The XML element we should load
+ * @return static
+ *
+ * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
+ * If the qualified name of the supplied element is wrong
+ */
+ public static function fromXML(DOMElement $xml): static
+ {
+ Assert::same($xml->localName, static::getLocalName(), InvalidDOMElementException::class);
+ Assert::same($xml->namespaceURI, static::NS, InvalidDOMElementException::class);
+ Assert::numeric($xml->textContent);
+
+ return new static(intval($xml->textContent));
+ }
+
+
+ /**
+ * Convert this element to XML.
+ *
+ * @param \DOMElement|null $parent The element we should append this element to.
+ * @return \DOMElement
+ */
+ public function toXML(?DOMElement $parent = null): DOMElement
+ {
+ $e = $this->instantiateParentElement($parent);
+ $e->textContent = strval($this->getIterationCount());
+
+ return $e;
+ }
+}
diff --git a/src/XML/xenc11/KeyDerivationMethod.php b/src/XML/xenc11/KeyDerivationMethod.php
new file mode 100644
index 00000000..a3652f79
--- /dev/null
+++ b/src/XML/xenc11/KeyDerivationMethod.php
@@ -0,0 +1,14 @@
+keyLength;
+ }
+
+
+ /**
+ * Convert XML into a class instance
+ *
+ * @param \DOMElement $xml The XML element we should load
+ * @return static
+ *
+ * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
+ * If the qualified name of the supplied element is wrong
+ */
+ public static function fromXML(DOMElement $xml): static
+ {
+ Assert::same($xml->localName, static::getLocalName(), InvalidDOMElementException::class);
+ Assert::same($xml->namespaceURI, static::NS, InvalidDOMElementException::class);
+ Assert::numeric($xml->textContent);
+
+ return new static(intval($xml->textContent));
+ }
+
+
+ /**
+ * Convert this element to XML.
+ *
+ * @param \DOMElement|null $parent The element we should append this element to.
+ * @return \DOMElement
+ */
+ public function toXML(?DOMElement $parent = null): DOMElement
+ {
+ $e = $this->instantiateParentElement($parent);
+ $e->textContent = strval($this->getKeyLength());
+
+ return $e;
+ }
+}
diff --git a/src/XML/xenc11/MGF.php b/src/XML/xenc11/MGF.php
new file mode 100644
index 00000000..5b34c964
--- /dev/null
+++ b/src/XML/xenc11/MGF.php
@@ -0,0 +1,33 @@
+localName, static::getLocalName(), InvalidDOMElementException::class);
+ Assert::same($xml->namespaceURI, static::getNamespaceURI(), InvalidDOMElementException::class);
+
+ return new static(
+ self::getOptionalAttribute($xml, 'Algorithm', null),
+ );
+ }
+}
diff --git a/src/XML/xenc11/MasterKeyName.php b/src/XML/xenc11/MasterKeyName.php
new file mode 100644
index 00000000..6f079faf
--- /dev/null
+++ b/src/XML/xenc11/MasterKeyName.php
@@ -0,0 +1,26 @@
+setContent($content);
+ }
+}
diff --git a/src/XML/xenc11/OtherSource.php b/src/XML/xenc11/OtherSource.php
new file mode 100644
index 00000000..f3527eda
--- /dev/null
+++ b/src/XML/xenc11/OtherSource.php
@@ -0,0 +1,40 @@
+localName, static::getLocalName(), InvalidDOMElementException::class);
+ Assert::same($xml->namespaceURI, static::getNamespaceURI(), InvalidDOMElementException::class);
+
+ $parameter = Parameters::getChildrenOfClass($xml);
+ Assert::maxCount($parameter, 1, TooManyElementsException::class);
+
+ return new static(
+ self::getOptionalAttribute($xml, 'Algorithm', null),
+ array_pop($parameter),
+ );
+ }
+}
diff --git a/src/XML/xenc11/PBKDF2params.php b/src/XML/xenc11/PBKDF2params.php
new file mode 100644
index 00000000..72c77c7b
--- /dev/null
+++ b/src/XML/xenc11/PBKDF2params.php
@@ -0,0 +1,16 @@
+localName, static::getLocalName(), InvalidDOMElementException::class);
+ Assert::same($xml->namespaceURI, static::getNamespaceURI(), InvalidDOMElementException::class);
+
+ return new static(
+ self::getOptionalAttribute($xml, 'Algorithm', null),
+ );
+ }
+}
diff --git a/src/XML/xenc11/Parameters.php b/src/XML/xenc11/Parameters.php
new file mode 100644
index 00000000..13e5da69
--- /dev/null
+++ b/src/XML/xenc11/Parameters.php
@@ -0,0 +1,99 @@
+ $elements
+ * @param array<\SimpleSAML\XML\Attribute> $attributes
+ */
+ public function __construct(array $elements = [], array $attributes = [])
+ {
+ $this->setElements($elements);
+ $this->setAttributesNS($attributes);
+ }
+
+
+
+ /**
+ * Test if an object, at the state it's in, would produce an empty XML-element
+ *
+ * @return bool
+ */
+ public function isEmptyElement(): bool
+ {
+ return empty($this->getAttributesNS())
+ && empty($this->getElements());
+ }
+
+
+ /**
+ * Convert XML into a Parameters element
+ *
+ * @param \DOMElement $xml The XML element we should load
+ * @return static
+ *
+ * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
+ * if the qualified name of the supplied element is wrong
+ */
+ public static function fromXML(DOMElement $xml): static
+ {
+ Assert::same($xml->localName, 'Parameters', InvalidDOMElementException::class);
+ Assert::same($xml->namespaceURI, Parameters::NS, InvalidDOMElementException::class);
+
+ return new static(
+ self::getChildElementsFromXML($xml),
+ self::getAttributesNSFromXML($xml),
+ );
+ }
+
+
+ /**
+ * Convert this Parameters element to XML.
+ *
+ * @param \DOMElement|null $parent The element we should append this Parameters to.
+ * @return \DOMElement
+ */
+ public function toXML(?DOMElement $parent = null): DOMElement
+ {
+ $e = $this->instantiateParentElement($parent);
+
+ foreach ($this->getAttributesNS() as $attr) {
+ $attr->toXML($e);
+ }
+
+ foreach ($this->getElements() as $element) {
+ /** @psalm-var \SimpleSAML\XML\SerializableElementInterface $element */
+ $element->toXML($e);
+ }
+
+ return $e;
+ }
+}
diff --git a/src/XML/xenc11/Salt.php b/src/XML/xenc11/Salt.php
new file mode 100644
index 00000000..444d75a9
--- /dev/null
+++ b/src/XML/xenc11/Salt.php
@@ -0,0 +1,77 @@
+.
+ *
+ * @package simplesamlphp/xml-security
+ */
+final class Salt extends AbstractXenc11Element
+{
+ /**
+ * Salt constructor.
+ *
+ * @param \SimpleSAML\XMLSecurity\XML\xenc11\OtherSource|\SimpleSAML\XMLSecurity\XML\xenc11\Specified $content
+ */
+ public function __construct(
+ protected OtherSource|Specified $content,
+ ) {
+ }
+
+
+ /**
+ * Get the value of the $content property.
+ *
+ * @return \SimpleSAML\XMLSecurity\XML\xenc11\OtherSource|\SimpleSAML\XMLSecurity\XML\xenc11\Specified
+ */
+ public function getContent(): OtherSource|Specified
+ {
+ return $this->content;
+ }
+
+
+ /**
+ * @inheritDoc
+ *
+ * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
+ * If the qualified name of the supplied element is wrong
+ */
+ public static function fromXML(DOMElement $xml): static
+ {
+ Assert::same($xml->localName, static::getLocalName(), InvalidDOMElementException::class);
+ Assert::same($xml->namespaceURI, static::getNamespaceURI(), InvalidDOMElementException::class);
+
+ $otherSource = OtherSource::getChildrenOfClass($xml);
+ $specified = Specified::getChildrenOfClass($xml);
+
+ $content = array_merge($otherSource, $specified);
+ Assert::minCount($content, 1, MissingElementException::class);
+ Assert::maxCount($content, 1, TooManyElementsException::class);
+
+ return new static(array_pop($content));
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public function toXML(?DOMElement $parent = null): DOMElement
+ {
+ $e = $this->instantiateParentElement($parent);
+ $this->getContent()->toXML($e);
+
+ return $e;
+ }
+}
diff --git a/src/XML/xenc11/Specified.php b/src/XML/xenc11/Specified.php
new file mode 100644
index 00000000..14ff6437
--- /dev/null
+++ b/src/XML/xenc11/Specified.php
@@ -0,0 +1,26 @@
+setContent($content);
+ }
+}
diff --git a/tests/XML/xenc11/ConcatKDFParamsTest.php b/tests/XML/xenc11/ConcatKDFParamsTest.php
new file mode 100644
index 00000000..37bb9f07
--- /dev/null
+++ b/tests/XML/xenc11/ConcatKDFParamsTest.php
@@ -0,0 +1,76 @@
+Random',
+ )->documentElement),
+ ],
+ );
+
+ $concatKdfParams = new ConcatKDFParams(
+ $digestMethod,
+ 'a1b2',
+ 'b2c3',
+ 'c3d4',
+ 'd4e5',
+ 'e5f6',
+ );
+
+ $this->assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($concatKdfParams),
+ );
+ }
+}
diff --git a/tests/XML/xenc11/DerivedKeyNameTest.php b/tests/XML/xenc11/DerivedKeyNameTest.php
new file mode 100644
index 00000000..ccd95a8f
--- /dev/null
+++ b/tests/XML/xenc11/DerivedKeyNameTest.php
@@ -0,0 +1,51 @@
+assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($derivedKeyName),
+ );
+ }
+}
diff --git a/tests/XML/xenc11/DerivedKeyTest.php b/tests/XML/xenc11/DerivedKeyTest.php
new file mode 100644
index 00000000..3a275b58
--- /dev/null
+++ b/tests/XML/xenc11/DerivedKeyTest.php
@@ -0,0 +1,184 @@
+assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($derivedKey),
+ );
+ }
+
+
+ /**
+ */
+ public function testMarshallingElementOrder(): void
+ {
+ $alg = 'http://www.w3.org/2009/xmlenc11#ConcatKDF';
+ $keyName = new KeyName('testkey');
+
+ $keyDerivationMethod = new KeyDerivationMethod($alg, [$keyName]);
+
+ $transformData = new Transform(
+ C::XPATH10_URI,
+ new XPath('self::xenc:EncryptedData[@Id="example1"]'),
+ );
+ $transformKey = new Transform(
+ C::XPATH10_URI,
+ new XPath('self::xenc:EncryptedKey[@Id="example1"]'),
+ );
+
+ $referenceList = new ReferenceList(
+ [
+ new DataReference('#Encrypted_DATA_ID', [new Transforms([$transformData])]),
+ ],
+ [
+ new KeyReference('#Encrypted_KEY_ID', [new Transforms([$transformKey])]),
+ ],
+ );
+
+ $derivedKeyName = new DerivedKeyName('phpunit');
+ $masterKeyName = new MasterKeyName('phpunit');
+
+ $derivedKey = new DerivedKey(
+ 'phpunit',
+ 'phpunit',
+ 'urn:x-simplesamlphp:type',
+ $keyDerivationMethod,
+ $referenceList,
+ $derivedKeyName,
+ $masterKeyName,
+ );
+
+ $dkElement = $derivedKey->toXML();
+ $xpCache = XPathUtils::getXPath($dkElement);
+
+ // Test for a KeyDerivationMethod
+ /** @var \DOMElement[] $keyDerivationMethodElements */
+ $keyDerivationMethodElements = XPathUtils::xpQuery($dkElement, './xenc11:KeyDerivationMethod', $xpCache);
+ $this->assertCount(1, $keyDerivationMethodElements);
+
+ // Test ordering of DerivedKey contents
+ /** @var \DOMElement[] $dkElements */
+ $dkElements = XPathUtils::xpQuery($dkElement, './xenc11:KeyDerivationMethod/following-sibling::*', $xpCache);
+
+ $this->assertCount(3, $dkElements);
+ $this->assertEquals('xenc:ReferenceList', $dkElements[0]->tagName);
+ $this->assertEquals('xenc11:DerivedKeyName', $dkElements[1]->tagName);
+ $this->assertEquals('xenc11:MasterKeyName', $dkElements[2]->tagName);
+ }
+
+
+ /**
+ * Adding an empty DerivedKey element should yield an empty element.
+ */
+ public function testMarshallingEmptyElement(): void
+ {
+ $xenc11_ns = DerivedKey::NS;
+ $derivedKey = new DerivedKey();
+ $this->assertEquals(
+ "",
+ strval($derivedKey),
+ );
+ $this->assertTrue($derivedKey->isEmptyElement());
+ }
+}
diff --git a/tests/XML/xenc11/IterationCountTest.php b/tests/XML/xenc11/IterationCountTest.php
new file mode 100644
index 00000000..2138b88f
--- /dev/null
+++ b/tests/XML/xenc11/IterationCountTest.php
@@ -0,0 +1,51 @@
+assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($iterationCount),
+ );
+ }
+}
diff --git a/tests/XML/xenc11/KeyDerivationMethodTest.php b/tests/XML/xenc11/KeyDerivationMethodTest.php
new file mode 100644
index 00000000..30fe4f57
--- /dev/null
+++ b/tests/XML/xenc11/KeyDerivationMethodTest.php
@@ -0,0 +1,68 @@
+assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($kdm),
+ );
+ }
+}
diff --git a/tests/XML/xenc11/KeyLengthTest.php b/tests/XML/xenc11/KeyLengthTest.php
new file mode 100644
index 00000000..43950f2d
--- /dev/null
+++ b/tests/XML/xenc11/KeyLengthTest.php
@@ -0,0 +1,51 @@
+assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($keyLength),
+ );
+ }
+}
diff --git a/tests/XML/xenc11/MGFTest.php b/tests/XML/xenc11/MGFTest.php
new file mode 100644
index 00000000..475cfdda
--- /dev/null
+++ b/tests/XML/xenc11/MGFTest.php
@@ -0,0 +1,62 @@
+assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($mgf),
+ );
+ }
+}
diff --git a/tests/XML/xenc11/MasterKeyNameTest.php b/tests/XML/xenc11/MasterKeyNameTest.php
new file mode 100644
index 00000000..c8d87668
--- /dev/null
+++ b/tests/XML/xenc11/MasterKeyNameTest.php
@@ -0,0 +1,51 @@
+assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($masterKeyName),
+ );
+ }
+}
diff --git a/tests/XML/xenc11/OtherSourceTest.php b/tests/XML/xenc11/OtherSourceTest.php
new file mode 100644
index 00000000..15271539
--- /dev/null
+++ b/tests/XML/xenc11/OtherSourceTest.php
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+XML
+ ,
+ )->documentElement);
+
+ $parameters = new Parameters(
+ [$chunk],
+ [new XMLAttribute('urn:x-simplesamlphp:namespace', 'ssp', 'attr1', 'testval1')],
+ );
+
+ $otherSource = new OtherSource('urn:x-simplesamlphp:algorithm', $parameters);
+
+ $this->assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($otherSource),
+ );
+ }
+}
diff --git a/tests/XML/xenc11/PBKDF2paramsTest.php b/tests/XML/xenc11/PBKDF2paramsTest.php
new file mode 100644
index 00000000..ca51216a
--- /dev/null
+++ b/tests/XML/xenc11/PBKDF2paramsTest.php
@@ -0,0 +1,84 @@
+Some',
+ );
+
+ $parameters = new Parameters(
+ [new Chunk($someDoc->documentElement)],
+ [new XMLAttribute('urn:x-simplesamlphp:namespace', 'ssp', 'attr1', 'testval1')],
+ );
+
+ $otherSource = new OtherSource('urn:x-simplesamlphp:algorithm', $parameters);
+
+ $salt = new Salt($otherSource);
+ $iterationCount = new IterationCount(3);
+ $keyLength = new KeyLength(4096);
+ $prf = new PRF('urn:x-simplesamlphp:algorithm');
+
+ $PBKDF2params = new PBKDF2params($salt, $iterationCount, $keyLength, $prf);
+
+ $this->assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($PBKDF2params),
+ );
+ }
+}
diff --git a/tests/XML/xenc11/PRFTest.php b/tests/XML/xenc11/PRFTest.php
new file mode 100644
index 00000000..b550794f
--- /dev/null
+++ b/tests/XML/xenc11/PRFTest.php
@@ -0,0 +1,58 @@
+assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($prf),
+ );
+ }
+}
diff --git a/tests/XML/xenc11/ParametersTest.php b/tests/XML/xenc11/ParametersTest.php
new file mode 100644
index 00000000..f5717045
--- /dev/null
+++ b/tests/XML/xenc11/ParametersTest.php
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+XML
+ ,
+ )->documentElement);
+
+ $parameters = new Parameters(
+ [$chunk],
+ [new XMLAttribute('urn:x-simplesamlphp:namespace', 'ssp', 'attr1', 'testval1')],
+ );
+
+ $this->assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($parameters),
+ );
+ }
+
+
+ /**
+ * Adding an empty Parameters element should yield an empty element.
+ */
+ public function testMarshallingEmptyElement(): void
+ {
+ $xenc11_ns = Parameters::NS;
+ $parameters = new Parameters();
+ $this->assertEquals(
+ "",
+ strval($parameters),
+ );
+ $this->assertTrue($parameters->isEmptyElement());
+ }
+}
diff --git a/tests/XML/xenc11/SaltTest.php b/tests/XML/xenc11/SaltTest.php
new file mode 100644
index 00000000..dda8c842
--- /dev/null
+++ b/tests/XML/xenc11/SaltTest.php
@@ -0,0 +1,68 @@
+Some',
+ );
+
+ $parameters = new Parameters(
+ [new Chunk($someDoc->documentElement)],
+ [new XMLAttribute('urn:x-simplesamlphp:namespace', 'ssp', 'attr1', 'testval1')],
+ );
+
+ $otherSource = new OtherSource('urn:x-simplesamlphp:algorithm', $parameters);
+ $salt = new Salt($otherSource);
+
+ $this->assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($salt),
+ );
+ }
+}
diff --git a/tests/XML/xenc11/SpecifiedTest.php b/tests/XML/xenc11/SpecifiedTest.php
new file mode 100644
index 00000000..b6c58109
--- /dev/null
+++ b/tests/XML/xenc11/SpecifiedTest.php
@@ -0,0 +1,51 @@
+assertEquals(
+ self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement),
+ strval($specified),
+ );
+ }
+}
diff --git a/tests/resources/xml/xenc11_ConcatKDFParams.xml b/tests/resources/xml/xenc11_ConcatKDFParams.xml
new file mode 100644
index 00000000..0d43622b
--- /dev/null
+++ b/tests/resources/xml/xenc11_ConcatKDFParams.xml
@@ -0,0 +1,5 @@
+
+
+ Random
+
+
diff --git a/tests/resources/xml/xenc11_DerivedKey.xml b/tests/resources/xml/xenc11_DerivedKey.xml
new file mode 100644
index 00000000..943219e4
--- /dev/null
+++ b/tests/resources/xml/xenc11_DerivedKey.xml
@@ -0,0 +1,23 @@
+
+
+ testkey
+
+
+
+
+
+ self::xenc:EncryptedData[@Id="example1"]
+
+
+
+
+
+
+ self::xenc:EncryptedKey[@Id="example1"]
+
+
+
+
+ phpunit
+ phpunit
+
diff --git a/tests/resources/xml/xenc11_DerivedKeyName.xml b/tests/resources/xml/xenc11_DerivedKeyName.xml
new file mode 100644
index 00000000..a219ef3c
--- /dev/null
+++ b/tests/resources/xml/xenc11_DerivedKeyName.xml
@@ -0,0 +1 @@
+phpunit
diff --git a/tests/resources/xml/xenc11_IterationCount.xml b/tests/resources/xml/xenc11_IterationCount.xml
new file mode 100644
index 00000000..55139a18
--- /dev/null
+++ b/tests/resources/xml/xenc11_IterationCount.xml
@@ -0,0 +1 @@
+3
diff --git a/tests/resources/xml/xenc11_KeyDerivationMethod.xml b/tests/resources/xml/xenc11_KeyDerivationMethod.xml
new file mode 100644
index 00000000..eced1d6c
--- /dev/null
+++ b/tests/resources/xml/xenc11_KeyDerivationMethod.xml
@@ -0,0 +1,3 @@
+
+ testkey
+
diff --git a/tests/resources/xml/xenc11_KeyLength.xml b/tests/resources/xml/xenc11_KeyLength.xml
new file mode 100644
index 00000000..1b8d4b63
--- /dev/null
+++ b/tests/resources/xml/xenc11_KeyLength.xml
@@ -0,0 +1 @@
+4096
diff --git a/tests/resources/xml/xenc11_MGF.xml b/tests/resources/xml/xenc11_MGF.xml
new file mode 100644
index 00000000..8b5cd146
--- /dev/null
+++ b/tests/resources/xml/xenc11_MGF.xml
@@ -0,0 +1 @@
+
diff --git a/tests/resources/xml/xenc11_MasterKeyName.xml b/tests/resources/xml/xenc11_MasterKeyName.xml
new file mode 100644
index 00000000..84f524e6
--- /dev/null
+++ b/tests/resources/xml/xenc11_MasterKeyName.xml
@@ -0,0 +1 @@
+phpunit
diff --git a/tests/resources/xml/xenc11_OtherSource.xml b/tests/resources/xml/xenc11_OtherSource.xml
new file mode 100644
index 00000000..434949ad
--- /dev/null
+++ b/tests/resources/xml/xenc11_OtherSource.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/resources/xml/xenc11_PBKDF2-params.xml b/tests/resources/xml/xenc11_PBKDF2-params.xml
new file mode 100644
index 00000000..d9676f0b
--- /dev/null
+++ b/tests/resources/xml/xenc11_PBKDF2-params.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ Some
+
+
+
+ 3
+ 4096
+
+
diff --git a/tests/resources/xml/xenc11_PRF.xml b/tests/resources/xml/xenc11_PRF.xml
new file mode 100644
index 00000000..1a75c6ee
--- /dev/null
+++ b/tests/resources/xml/xenc11_PRF.xml
@@ -0,0 +1 @@
+
diff --git a/tests/resources/xml/xenc11_Parameters.xml b/tests/resources/xml/xenc11_Parameters.xml
new file mode 100644
index 00000000..9fa64931
--- /dev/null
+++ b/tests/resources/xml/xenc11_Parameters.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/tests/resources/xml/xenc11_Salt.xml b/tests/resources/xml/xenc11_Salt.xml
new file mode 100644
index 00000000..ce5c7dac
--- /dev/null
+++ b/tests/resources/xml/xenc11_Salt.xml
@@ -0,0 +1,7 @@
+
+
+
+ Some
+
+
+
diff --git a/tests/resources/xml/xenc11_Specified.xml b/tests/resources/xml/xenc11_Specified.xml
new file mode 100644
index 00000000..9c86d459
--- /dev/null
+++ b/tests/resources/xml/xenc11_Specified.xml
@@ -0,0 +1 @@
+GpM6