diff --git a/src/XML/element.registry.php b/src/XML/element.registry.php index c83bd98c..9a55180d 100644 --- a/src/XML/element.registry.php +++ b/src/XML/element.registry.php @@ -46,7 +46,7 @@ 'AgreementMethod' => '\SimpleSAML\XMLSecurity\XML\xenc\AgreementMethod', 'CipherData' => '\SimpleSAML\XMLSecurity\XML\xenc\CipherData', 'CipherReference' => '\SimpleSAML\XMLSecurity\XML\xenc\CipherReference', -// 'DHKeyValue' => '\SimpleSAML\XMLSecurity\XML\xenc\DHKeyValue', + 'DHKeyValue' => '\SimpleSAML\XMLSecurity\XML\xenc\DHKeyValue', 'EncryptedData' => '\SimpleSAML\XMLSecurity\XML\xenc\EncryptedData', 'EncryptedKey' => '\SimpleSAML\XMLSecurity\XML\xenc\EncryptedKey', 'EncryptionProperties' => '\SimpleSAML\XMLSecurity\XML\xenc\EncryptionProperties', diff --git a/src/XML/xenc/AbstractDHKeyValueType.php b/src/XML/xenc/AbstractDHKeyValueType.php new file mode 100644 index 00000000..66b60d81 --- /dev/null +++ b/src/XML/xenc/AbstractDHKeyValueType.php @@ -0,0 +1,188 @@ +xencPublic; + } + + + /** + * Get the P. + * + * @return \SimpleSAML\XMLSecurity\XML\xenc\P|null + */ + public function getP(): ?P + { + return $this->p; + } + + + /** + * Get the Q. + * + * @return \SimpleSAML\XMLSecurity\XML\xenc\Q|null + */ + public function getQ(): ?Q + { + return $this->q; + } + + + /** + * Get the Generator. + * + * @return \SimpleSAML\XMLSecurity\XML\xenc\Generator|null + */ + public function getGenerator(): ?Generator + { + return $this->generator; + } + + + /** + * Get the Seed. + * + * @return \SimpleSAML\XMLSecurity\XML\xenc\Seed|null + */ + public function getSeed(): ?Seed + { + return $this->seed; + } + + + /** + * Get the PgenCounter. + * + * @return \SimpleSAML\XMLSecurity\XML\xenc\PgenCounter|null + */ + public function getPgenCounter(): ?PgenCounter + { + return $this->pgenCounter; + } + + + /** + * Initialize an DHKeyValue object from an existing XML. + * + * @param \DOMElement $xml + * @return static + * + * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException + * if the qualified name of the supplied element is wrong + * @throws \SimpleSAML\XML\Exception\MissingAttributeException + * if the supplied element is missing one of the mandatory attributes + * @throws \SimpleSAML\XML\Exception\TooManyElementsException + * if too many child-elements of a type are specified + */ + public static function fromXML(DOMElement $xml): static + { + Assert::same($xml->localName, 'DHKeyValue', InvalidDOMElementException::class); + Assert::same($xml->namespaceURI, static::NS, InvalidDOMElementException::class); + + $xencPublic = XencPublic::getChildrenOfClass($xml); + Assert::minCount($xencPublic, 1, MissingElementException::class); + Assert::maxCount($xencPublic, 1, TooManyElementsException::class); + + $p = P::getChildrenOfClass($xml); + Assert::maxCount($p, 1, TooManyElementsException::class); + + $q = Q::getChildrenOfClass($xml); + Assert::maxCount($q, 1, TooManyElementsException::class); + + $generator = Generator::getChildrenOfClass($xml); + Assert::maxCount($generator, 1, TooManyElementsException::class); + + $seed = Seed::getChildrenOfClass($xml); + Assert::maxCount($seed, 1, TooManyElementsException::class); + + $pgenCounter = PgenCounter::getChildrenOfClass($xml); + Assert::maxCount($pgenCounter, 1, TooManyElementsException::class); + + return new static( + array_pop($xencPublic), + array_pop($p), + array_pop($q), + array_pop($generator), + array_pop($seed), + array_pop($pgenCounter), + ); + } + + + /** + * Convert this DHKeyValue object to XML. + * + * @param \DOMElement|null $parent The element we should append this DHKeyValue to. + * @return \DOMElement + */ + public function toXML(DOMElement $parent = null): DOMElement + { + $e = $this->instantiateParentElement($parent); + + $this->getP()?->toXML($e); + $this->getQ()?->toXML($e); + $this->getGenerator()?->toXML($e); + $this->getPublic()->toXML($e); + $this->getSeed()?->toXML($e); + $this->getPgenCounter()?->toXML($e); + + return $e; + } +} diff --git a/src/XML/xenc/DHKeyValue.php b/src/XML/xenc/DHKeyValue.php new file mode 100644 index 00000000..66ab7082 --- /dev/null +++ b/src/XML/xenc/DHKeyValue.php @@ -0,0 +1,14 @@ +assertEquals( + self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement), + strval($dhKeyValue), + ); + } + /** + */ + public function testMarshallingElementOrder(): void + { + $xencPublic = new XencPublic('/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + $p = new P('/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + $q = new Q('/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + $generator = new Generator('/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + $seed = new Seed('/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + $pgenCounter = new PgenCounter('/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + + $dhKeyValue = new DHKeyValue($xencPublic, $p, $q, $generator, $seed, $pgenCounter); + + // Marshall it to a \DOMElement + $dhKeyValueElement = $dhKeyValue->toXML(); + + $xpCache = XPath::getXPath($dhKeyValueElement); + + // Test for an P + /** @var \DOMElement[] $pElements */ + $pElements = XPath::xpQuery($dhKeyValueElement, './xenc:P', $xpCache); + $this->assertCount(1, $pElements); + + // Test ordering of DHKeyValue contents + /** @var \DOMElement[] $dhKeyValueElements */ + $dhKeyValueElements = XPath::xpQuery( + $dhKeyValueElement, + './xenc:P/following-sibling::*', + $xpCache, + ); + + $this->assertCount(5, $dhKeyValueElements); + $this->assertEquals('xenc:Q', $dhKeyValueElements[0]->tagName); + $this->assertEquals('xenc:Generator', $dhKeyValueElements[1]->tagName); + $this->assertEquals('xenc:Public', $dhKeyValueElements[2]->tagName); + $this->assertEquals('xenc:seed', $dhKeyValueElements[3]->tagName); + $this->assertEquals('xenc:pgenCounter', $dhKeyValueElements[4]->tagName); + } +} diff --git a/tests/resources/xml/xenc_DHKeyValue.xml b/tests/resources/xml/xenc_DHKeyValue.xml new file mode 100644 index 00000000..68e0969f --- /dev/null +++ b/tests/resources/xml/xenc_DHKeyValue.xml @@ -0,0 +1,8 @@ + + /CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI= + /CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI= + /CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI= + /CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI= + /CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI= + /CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI= +