diff --git a/src/Constants.php b/src/Constants.php index 1a1f2656..7b39c159 100644 --- a/src/Constants.php +++ b/src/Constants.php @@ -152,4 +152,7 @@ class Constants extends \SimpleSAML\XML\Constants public const XMLENC_ELEMENT = 'http://www.w3.org/2001/04/xmlenc#Element'; public const XMLENC_ENCRYPTEDKEY = 'http://www.w3.org/2001/04/xmlenc#EncryptedKey'; public const XMLENC_EXI = 'http://www.w3.org/2009/xmlenc11#EXI'; + + // The namespace for the Elliptic Curve Diffie-Hellman Ephemeral Static (ECDH-ES) algorithm + public const XMLENC11_ECDH_ES = 'http://www.w3.org/2009/xmlenc11#ECDH-ES'; } diff --git a/src/XML/ds/AbstractKeyInfoType.php b/src/XML/ds/AbstractKeyInfoType.php new file mode 100644 index 00000000..b266045f --- /dev/null +++ b/src/XML/ds/AbstractKeyInfoType.php @@ -0,0 +1,117 @@ +Id; + } + + + /** + * Collect the value of the info-property + * + * @return list<\SimpleSAML\XML\SerializableElementInterface> + */ + public function getInfo(): array + { + return $this->info; + } + + + /** + * Convert this KeyInfo to XML. + * + * @param \DOMElement|null $parent The element we should append this KeyInfo to. + * @return \DOMElement + */ + public function toXML(DOMElement $parent = null): DOMElement + { + $e = $this->instantiateParentElement($parent); + + if ($this->getId() !== null) { + $e->setAttribute('Id', $this->getId()); + } + + foreach ($this->getInfo() as $elt) { + $elt->toXML($e); + } + + return $e; + } +} diff --git a/src/XML/ds/KeyInfo.php b/src/XML/ds/KeyInfo.php index 1c013590..5f499345 100644 --- a/src/XML/ds/KeyInfo.php +++ b/src/XML/ds/KeyInfo.php @@ -7,86 +7,16 @@ use DOMElement; use SimpleSAML\Assert\Assert; use SimpleSAML\XML\Exception\InvalidDOMElementException; -use SimpleSAML\XML\Exception\SchemaViolationException; -use SimpleSAML\XML\ExtendableElementTrait; -use SimpleSAML\XML\SerializableElementInterface; -use SimpleSAML\XML\XsNamespace as NS; -use SimpleSAML\XMLSecurity\Constants as C; -use SimpleSAML\XMLSecurity\Exception\InvalidArgumentException; -use SimpleSAML\XMLSecurity\XML\ds\AbstractDsElement; + +use function array_merge; /** * Class representing a ds:KeyInfo element. * * @package simplesamlphp/xml-security */ -final class KeyInfo extends AbstractDsElement +final class KeyInfo extends AbstractKeyInfoType { - use ExtendableElementTrait; - - /** @var \SimpleSAML\XML\XsNamespace */ - public const XS_ANY_ELT_NAMESPACE = NS::OTHER; - - - /** - * Initialize a KeyInfo element. - * - * @param ( - * \SimpleSAML\XMLSecurity\XML\ds\KeyName| - * \SimpleSAML\XMLSecurity\XML\ds\KeyValue| - * \SimpleSAML\XMLSecurity\XML\ds\RetrievalMethod| - * \SimpleSAML\XMLSecurity\XML\ds\X509Data| - * \SimpleSAML\XML\SerializableElementInterface - * )[] $info - * @param string|null $Id - */ - public function __construct( - protected array $info, - protected ?string $Id = null, - ) { - Assert::notEmpty($info, 'ds:KeyInfo cannot be empty', InvalidArgumentException::class); - Assert::maxCount($info, C::UNBOUNDED_LIMIT); - Assert::allIsInstanceOf( - $info, - SerializableElementInterface::class, - InvalidArgumentException::class, - ); - Assert::nullOrValidNCName($Id); - - foreach ($info as $item) { - if ($item instanceof AbstractDsElement) { - Assert::isInstanceOfAny( - $item, - [KeyName::class, KeyValue::class, RetrievalMethod::class, X509Data::class], - SchemaViolationException::class, - ); - } - } - } - - - /** - * Collect the value of the Id-property - * - * @return string|null - */ - public function getId(): ?string - { - return $this->Id; - } - - - /** - * Collect the value of the info-property - * - * @return list<\SimpleSAML\XML\SerializableElementInterface> - */ - public function getInfo(): array - { - return $this->info; - } - - /** * Convert XML into a KeyInfo * @@ -125,26 +55,4 @@ public static function fromXML(DOMElement $xml): static return new static($info, $Id); } - - - /** - * Convert this KeyInfo to XML. - * - * @param \DOMElement|null $parent The element we should append this KeyInfo to. - * @return \DOMElement - */ - public function toXML(DOMElement $parent = null): DOMElement - { - $e = $this->instantiateParentElement($parent); - - if ($this->getId() !== null) { - $e->setAttribute('Id', $this->getId()); - } - - foreach ($this->getInfo() as $elt) { - $elt->toXML($e); - } - - return $e; - } } diff --git a/src/XML/element.registry.php b/src/XML/element.registry.php index 5a371ef8..9a55180d 100644 --- a/src/XML/element.registry.php +++ b/src/XML/element.registry.php @@ -43,10 +43,10 @@ 'InclusiveNamespaces' => '\SimpleSAML\XMLSecurity\XML\ec\InclusiveNamespaces', ], 'http://www.w3.org/2001/04/xmlenc#' => [ -// 'AgreementMethod' => '\SimpleSAML\XMLSecurity\XML\xenc\AgreementMethod', + '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/AbstractAgreementMethodType.php b/src/XML/xenc/AbstractAgreementMethodType.php new file mode 100644 index 00000000..009887d0 --- /dev/null +++ b/src/XML/xenc/AbstractAgreementMethodType.php @@ -0,0 +1,159 @@ + $children + */ + final public function __construct( + protected string $algorithm, + protected ?KANonce $kaNonce = null, + protected ?OriginatorKeyInfo $originatorKeyInfo = null, + protected ?RecipientKeyInfo $recipientKeyInfo = null, + protected array $children = [], + ) { + Assert::validURI($algorithm, SchemaViolationException::class); // Covers the empty string + + $this->setElements($children); + } + + + /** + * Get the URI identifying the algorithm used by this agreement method. + * + * @return string + */ + public function getAlgorithm(): string + { + return $this->algorithm; + } + + + /** + * Get the KA-Nonce. + * + * @return \SimpleSAML\XMLSecurity\XML\xenc\KANonce|null + */ + public function getKANonce(): ?KANonce + { + return $this->kaNonce; + } + + + /** + * Get the Originator KeyInfo. + * + * @return \SimpleSAML\XMLSecurity\XML\xenc\OriginatorKeyInfo|null + */ + public function getOriginatorKeyInfo(): ?OriginatorKeyInfo + { + return $this->originatorKeyInfo; + } + + + /** + * Get the Recipient KeyInfo. + * + * @return \SimpleSAML\XMLSecurity\XML\xenc\RecipientKeyInfo|null + */ + public function getRecipientKeyInfo(): ?RecipientKeyInfo + { + return $this->recipientKeyInfo; + } + + + /** + * Initialize an AgreementMethod 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, 'AgreementMethod', InvalidDOMElementException::class); + Assert::same($xml->namespaceURI, static::NS, InvalidDOMElementException::class); + + $algorithm = self::getAttribute($xml, 'Algorithm'); + + $kaNonce = KANonce::getChildrenOfClass($xml); + Assert::maxCount($kaNonce, 1, TooManyElementsException::class); + + $originatorKeyInfo = OriginatorKeyInfo::getChildrenOfClass($xml); + Assert::maxCount($originatorKeyInfo, 1, TooManyElementsException::class); + + $recipientKeyInfo = RecipientKeyInfo::getChildrenOfClass($xml); + Assert::maxCount($recipientKeyInfo, 1, TooManyElementsException::class); + + $children = self::getChildElementsFromXML($xml); + + return new static( + $algorithm, + array_pop($kaNonce), + array_pop($originatorKeyInfo), + array_pop($recipientKeyInfo), + $children, + ); + } + + + /** + * Convert this AgreementMethod object to XML. + * + * @param \DOMElement|null $parent The element we should append this AgreementMethod to. + * @return \DOMElement + */ + public function toXML(DOMElement $parent = null): DOMElement + { + $e = $this->instantiateParentElement($parent); + $e->setAttribute('Algorithm', $this->getAlgorithm()); + + $this->getKANonce()?->toXML($e); + + foreach ($this->getElements() as $child) { + $child->toXML($e); + } + + $this->getOriginatorKeyInfo()?->toXML($e); + $this->getRecipientKeyInfo()?->toXML($e); + + return $e; + } +} 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/AgreementMethod.php b/src/XML/xenc/AgreementMethod.php new file mode 100644 index 00000000..3a7bc106 --- /dev/null +++ b/src/XML/xenc/AgreementMethod.php @@ -0,0 +1,14 @@ +setContent($content); + } +} diff --git a/src/XML/xenc/KANonce.php b/src/XML/xenc/KANonce.php new file mode 100644 index 00000000..44e72e2a --- /dev/null +++ b/src/XML/xenc/KANonce.php @@ -0,0 +1,29 @@ +setContent($content); + } +} diff --git a/src/XML/xenc/OriginatorKeyInfo.php b/src/XML/xenc/OriginatorKeyInfo.php new file mode 100644 index 00000000..2f7db9a1 --- /dev/null +++ b/src/XML/xenc/OriginatorKeyInfo.php @@ -0,0 +1,71 @@ +localName, 'OriginatorKeyInfo', InvalidDOMElementException::class); + Assert::same($xml->namespaceURI, OriginatorKeyInfo::NS, InvalidDOMElementException::class); + + $Id = self::getOptionalAttribute($xml, 'Id', null); + + $keyName = KeyName::getChildrenOfClass($xml); + $keyValue = KeyValue::getChildrenOfClass($xml); + $retrievalMethod = RetrievalMethod::getChildrenOfClass($xml); + $x509Data = X509Data::getChildrenOfClass($xml); + //$pgpData = PGPData::getChildrenOfClass($xml); + //$spkiData = SPKIData::getChildrenOfClass($xml); + //$mgmtData = MgmtData::getChildrenOfClass($xml); + $other = self::getChildElementsFromXML($xml); + + $info = array_merge( + $keyName, + $keyValue, + $retrievalMethod, + $x509Data, + //$pgpdata, + //$spkidata, + //$mgmtdata, + $other, + ); + + return new static($info, $Id); + } +} diff --git a/src/XML/xenc/P.php b/src/XML/xenc/P.php new file mode 100644 index 00000000..a9f4a530 --- /dev/null +++ b/src/XML/xenc/P.php @@ -0,0 +1,26 @@ +setContent($content); + } +} diff --git a/src/XML/xenc/PgenCounter.php b/src/XML/xenc/PgenCounter.php new file mode 100644 index 00000000..5350a3c4 --- /dev/null +++ b/src/XML/xenc/PgenCounter.php @@ -0,0 +1,29 @@ +setContent($content); + } +} diff --git a/src/XML/xenc/Q.php b/src/XML/xenc/Q.php new file mode 100644 index 00000000..379ecb54 --- /dev/null +++ b/src/XML/xenc/Q.php @@ -0,0 +1,26 @@ +setContent($content); + } +} diff --git a/src/XML/xenc/RecipientKeyInfo.php b/src/XML/xenc/RecipientKeyInfo.php new file mode 100644 index 00000000..c5eb61b9 --- /dev/null +++ b/src/XML/xenc/RecipientKeyInfo.php @@ -0,0 +1,71 @@ +localName, 'RecipientKeyInfo', InvalidDOMElementException::class); + Assert::same($xml->namespaceURI, RecipientKeyInfo::NS, InvalidDOMElementException::class); + + $Id = self::getOptionalAttribute($xml, 'Id', null); + + $keyName = KeyName::getChildrenOfClass($xml); + $keyValue = KeyValue::getChildrenOfClass($xml); + $retrievalMethod = RetrievalMethod::getChildrenOfClass($xml); + $x509Data = X509Data::getChildrenOfClass($xml); + //$pgpData = PGPData::getChildrenOfClass($xml); + //$spkiData = SPKIData::getChildrenOfClass($xml); + //$mgmtData = MgmtData::getChildrenOfClass($xml); + $other = self::getChildElementsFromXML($xml); + + $info = array_merge( + $keyName, + $keyValue, + $retrievalMethod, + $x509Data, + //$pgpdata, + //$spkidata, + //$mgmtdata, + $other, + ); + + return new static($info, $Id); + } +} diff --git a/src/XML/xenc/Seed.php b/src/XML/xenc/Seed.php new file mode 100644 index 00000000..7eb7823a --- /dev/null +++ b/src/XML/xenc/Seed.php @@ -0,0 +1,29 @@ +setContent($content); + } +} diff --git a/src/XML/xenc/XencPublic.php b/src/XML/xenc/XencPublic.php new file mode 100644 index 00000000..d8169c0e --- /dev/null +++ b/src/XML/xenc/XencPublic.php @@ -0,0 +1,29 @@ +setContent($content); + } +} diff --git a/tests/XML/ds/KeyInfoTest.php b/tests/XML/ds/KeyInfoTest.php index e8e9f547..44e25513 100644 --- a/tests/XML/ds/KeyInfoTest.php +++ b/tests/XML/ds/KeyInfoTest.php @@ -13,6 +13,7 @@ use SimpleSAML\XMLSecurity\Exception\InvalidArgumentException; use SimpleSAML\XMLSecurity\TestUtils\PEMCertificatesMock; use SimpleSAML\XMLSecurity\XML\ds\AbstractDsElement; +use SimpleSAML\XMLSecurity\XML\ds\AbstractKeyInfoType; use SimpleSAML\XMLSecurity\XML\ds\KeyInfo; use SimpleSAML\XMLSecurity\XML\ds\KeyName; use SimpleSAML\XMLSecurity\XML\ds\X509Certificate; @@ -30,6 +31,7 @@ * @package simplesamlphp/xml-security */ #[CoversClass(AbstractDsElement::class)] +#[CoversClass(AbstractKeyInfoType::class)] #[CoversClass(KeyInfo::class)] final class KeyInfoTest extends TestCase { @@ -115,7 +117,7 @@ public function testMarshallingEmpty(): void $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('ds:KeyInfo cannot be empty'); - $keyInfo = new KeyInfo([]); + new KeyInfo([]); } @@ -128,6 +130,6 @@ public function testUnmarshallingEmpty(): void $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('ds:KeyInfo cannot be empty'); - $keyInfo = KeyInfo::fromXML($document->documentElement); + KeyInfo::fromXML($document->documentElement); } } diff --git a/tests/XML/xenc/AgreementMethodTest.php b/tests/XML/xenc/AgreementMethodTest.php new file mode 100644 index 00000000..46ec79dd --- /dev/null +++ b/tests/XML/xenc/AgreementMethodTest.php @@ -0,0 +1,220 @@ +some', + )->documentElement), + ], + ); + + $originatorKeyInfo = new OriginatorKeyInfo( + [ + new KeyName('testkey'), + new X509Data( + [ + new X509Certificate(self::$certificate), + new X509SubjectName(self::$certData['name']), + ], + ), + new Chunk(DOMDocumentFactory::fromString( + 'originator', + )->documentElement), + ], + 'fed123', + ); + + $recipientKeyInfo = new RecipientKeyInfo( + [ + new KeyName('testkey'), + new X509Data( + [ + new X509Certificate(self::$certificate), + new X509SubjectName(self::$certData['name']), + ], + ), + new Chunk(DOMDocumentFactory::fromString( + 'recipient', + )->documentElement), + ], + 'fed654', + ); + + $agreementMethod = new AgreementMethod( + C::XMLENC11_ECDH_ES, + $kaNonce, + $originatorKeyInfo, + $recipientKeyInfo, + [$digestMethod], + ); + + $this->assertEquals( + self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement), + strval($agreementMethod), + ); + } + + + public function testMarshallingElementOrdering(): void + { + $kaNonce = new KANonce('/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + + $digestMethod = new DigestMethod( + C::DIGEST_SHA256, + [ + new Chunk(DOMDocumentFactory::fromString( + 'some', + )->documentElement), + ], + ); + + $originatorKeyInfo = new OriginatorKeyInfo( + [ + new KeyName('testkey'), + new X509Data( + [ + new X509Certificate(self::$certificate), + new X509SubjectName(self::$certData['name']), + ], + ), + new Chunk(DOMDocumentFactory::fromString( + 'originator', + )->documentElement), + ], + 'fed321', + ); + + $recipientKeyInfo = new RecipientKeyInfo( + [ + new KeyName('testkey'), + new X509Data( + [ + new X509Certificate(self::$certificate), + new X509SubjectName(self::$certData['name']), + ], + ), + new Chunk(DOMDocumentFactory::fromString( + 'recipient', + )->documentElement), + ], + 'fed654', + ); + + $agreementMethod = new AgreementMethod( + C::XMLENC11_ECDH_ES, + $kaNonce, + $originatorKeyInfo, + $recipientKeyInfo, + [$digestMethod], + ); + + // Marshall it to a \DOMElement + $agreementMethodElement = $agreementMethod->toXML(); + + $xpCache = XPath::getXPath($agreementMethodElement); + + // Test for an KA-Nonce + /** @var \DOMElement[] $kaNonceElements */ + $kaNonceElements = XPath::xpQuery($agreementMethodElement, './xenc:KA-Nonce', $xpCache); + $this->assertCount(1, $kaNonceElements); + + // Test ordering of AgreementMethod contents + /** @var \DOMElement[] $agreementMethodElements */ + $agreementMethodElements = XPath::xpQuery( + $agreementMethodElement, + './xenc:KA-Nonce/following-sibling::*', + $xpCache, + ); + + $this->assertCount(3, $agreementMethodElements); + $this->assertEquals('ds:DigestMethod', $agreementMethodElements[0]->tagName); + $this->assertEquals('xenc:OriginatorKeyInfo', $agreementMethodElements[1]->tagName); + $this->assertEquals('xenc:RecipientKeyInfo', $agreementMethodElements[2]->tagName); + } +} diff --git a/tests/XML/xenc/DHKeyValueTest.php b/tests/XML/xenc/DHKeyValueTest.php new file mode 100644 index 00000000..7545a420 --- /dev/null +++ b/tests/XML/xenc/DHKeyValueTest.php @@ -0,0 +1,113 @@ +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/XML/xenc/GeneratorTest.php b/tests/XML/xenc/GeneratorTest.php new file mode 100644 index 00000000..eb7e6c0d --- /dev/null +++ b/tests/XML/xenc/GeneratorTest.php @@ -0,0 +1,65 @@ +assertEquals( + XMLDumper::dumpDOMDocumentXMLWithBase64Content(self::$xmlRepresentation), + strval($generator), + ); + } + + + /** + */ + public function testMarshallingNotBase64(): void + { + $this->expectException(AssertionFailedException::class); + new Generator('/CTj3d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + } +} diff --git a/tests/XML/xenc/KANonceTest.php b/tests/XML/xenc/KANonceTest.php new file mode 100644 index 00000000..fb72c681 --- /dev/null +++ b/tests/XML/xenc/KANonceTest.php @@ -0,0 +1,65 @@ +assertEquals( + XMLDumper::dumpDOMDocumentXMLWithBase64Content(self::$xmlRepresentation), + strval($kaNonce), + ); + } + + + /** + */ + public function testMarshallingNotBase64(): void + { + $this->expectException(AssertionFailedException::class); + new KANonce('/CTj3d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + } +} diff --git a/tests/XML/xenc/OriginatorKeyInfoTest.php b/tests/XML/xenc/OriginatorKeyInfoTest.php new file mode 100644 index 00000000..69522d79 --- /dev/null +++ b/tests/XML/xenc/OriginatorKeyInfoTest.php @@ -0,0 +1,133 @@ +some', + )->documentElement), + ], + 'fed654', + ); + + $this->assertEquals( + self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement), + strval($originatorKeyInfo), + ); + } + + + /** + */ + public function testMarshallingEmpty(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('xenc:OriginatorKeyInfo cannot be empty'); + + new OriginatorKeyInfo([]); + } + + + /** + */ + public function testUnmarshallingEmpty(): void + { + $document = DOMDocumentFactory::fromString( + '', + ); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('xenc:OriginatorKeyInfo cannot be empty'); + + OriginatorKeyInfo::fromXML($document->documentElement); + } +} diff --git a/tests/XML/xenc/PTest.php b/tests/XML/xenc/PTest.php new file mode 100644 index 00000000..0e6c4cc8 --- /dev/null +++ b/tests/XML/xenc/PTest.php @@ -0,0 +1,65 @@ +assertEquals( + XMLDumper::dumpDOMDocumentXMLWithBase64Content(self::$xmlRepresentation), + strval($p), + ); + } + + + /** + */ + public function testMarshallingNotBase64(): void + { + $this->expectException(AssertionFailedException::class); + new P('/CTj3d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + } +} diff --git a/tests/XML/xenc/PgenCounterTest.php b/tests/XML/xenc/PgenCounterTest.php new file mode 100644 index 00000000..bf5b9652 --- /dev/null +++ b/tests/XML/xenc/PgenCounterTest.php @@ -0,0 +1,65 @@ +assertEquals( + XMLDumper::dumpDOMDocumentXMLWithBase64Content(self::$xmlRepresentation), + strval($pgenCounter), + ); + } + + + /** + */ + public function testMarshallingNotBase64(): void + { + $this->expectException(AssertionFailedException::class); + new PgenCounter('/CTj3d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + } +} diff --git a/tests/XML/xenc/PublicTest.php b/tests/XML/xenc/PublicTest.php new file mode 100644 index 00000000..425979d3 --- /dev/null +++ b/tests/XML/xenc/PublicTest.php @@ -0,0 +1,65 @@ +assertEquals( + XMLDumper::dumpDOMDocumentXMLWithBase64Content(self::$xmlRepresentation), + strval($public), + ); + } + + + /** + */ + public function testMarshallingNotBase64(): void + { + $this->expectException(AssertionFailedException::class); + new XencPublic('/CTj3d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + } +} diff --git a/tests/XML/xenc/QTest.php b/tests/XML/xenc/QTest.php new file mode 100644 index 00000000..46ddcb12 --- /dev/null +++ b/tests/XML/xenc/QTest.php @@ -0,0 +1,65 @@ +assertEquals( + XMLDumper::dumpDOMDocumentXMLWithBase64Content(self::$xmlRepresentation), + strval($q), + ); + } + + + /** + */ + public function testMarshallingNotBase64(): void + { + $this->expectException(AssertionFailedException::class); + new Q('/CTj3d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + } +} diff --git a/tests/XML/xenc/RecipientKeyInfoTest.php b/tests/XML/xenc/RecipientKeyInfoTest.php new file mode 100644 index 00000000..3fdce621 --- /dev/null +++ b/tests/XML/xenc/RecipientKeyInfoTest.php @@ -0,0 +1,133 @@ +some', + )->documentElement), + ], + 'fed654', + ); + + $this->assertEquals( + self::$xmlRepresentation->saveXML(self::$xmlRepresentation->documentElement), + strval($recipientKeyInfo), + ); + } + + + /** + */ + public function testMarshallingEmpty(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('xenc:RecipientKeyInfo cannot be empty'); + + new RecipientKeyInfo([]); + } + + + /** + */ + public function testUnmarshallingEmpty(): void + { + $document = DOMDocumentFactory::fromString( + '', + ); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('xenc:RecipientKeyInfo cannot be empty'); + + RecipientKeyInfo::fromXML($document->documentElement); + } +} diff --git a/tests/XML/xenc/SeedTest.php b/tests/XML/xenc/SeedTest.php new file mode 100644 index 00000000..03a581f1 --- /dev/null +++ b/tests/XML/xenc/SeedTest.php @@ -0,0 +1,65 @@ +assertEquals( + XMLDumper::dumpDOMDocumentXMLWithBase64Content(self::$xmlRepresentation), + strval($seed), + ); + } + + + /** + */ + public function testMarshallingNotBase64(): void + { + $this->expectException(AssertionFailedException::class); + new Seed('/CTj3d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI='); + } +} diff --git a/tests/resources/xml/xenc_AgreementMethod.xml b/tests/resources/xml/xenc_AgreementMethod.xml new file mode 100644 index 00000000..f4847ade --- /dev/null +++ b/tests/resources/xml/xenc_AgreementMethod.xml @@ -0,0 +1,22 @@ + + /CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI= + + some + + + testkey + + MIICxDCCAi2gAwIBAgIUZ9QDx+SBFHednUWDFGm9tyVKrgQwDQYJKoZIhvcNAQELBQAwczElMCMGA1UEAwwcc2VsZnNpZ25lZC5zaW1wbGVzYW1scGhwLm9yZzEZMBcGA1UECgwQU2ltcGxlU0FNTHBocCBIUTERMA8GA1UEBwwISG9ub2x1bHUxDzANBgNVBAgMBkhhd2FpaTELMAkGA1UEBhMCVVMwIBcNMjIxMjAzMTAzNTQwWhgPMjEyMjExMDkxMDM1NDBaMHMxJTAjBgNVBAMMHHNlbGZzaWduZWQuc2ltcGxlc2FtbHBocC5vcmcxGTAXBgNVBAoMEFNpbXBsZVNBTUxwaHAgSFExETAPBgNVBAcMCEhvbm9sdWx1MQ8wDQYDVQQIDAZIYXdhaWkxCzAJBgNVBAYTAlVTMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDessdFRVDTMQQW3Na81B1CjJV1tmY3nopoIhZrkbDxLa+pv7jGDRcYreyu1DoQxEs06V2nHLoyOPhqJXSFivqtUwVYhR6NYgbNI6RRSsIJCweH0YOdlHna7gULPcLX0Bfbi4odStaFwG9yzDySwSEPtsKxm5pENPjNVGh+jJ+H/QIDAQABo1MwUTAdBgNVHQ4EFgQUvV75t8EoQo2fVa0E9otdtIGK5X0wHwYDVR0jBBgwFoAUvV75t8EoQo2fVa0E9otdtIGK5X0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQANQUeiwPJXkWMXuaDHToEBKcezYGqGEYnGUi9LMjeb+Kln7X8nn5iknlz4k77rWCbSwLPC/WDr0ySYQA+HagaeUaFpoiYFJKS6uFlK1HYWnM3W4PUiGHg1/xeZlMO44wTwybXVo0y9KMhchfB5XNbDdoJcqWYvi6xtmZZNRbxUyw== + /CN=selfsigned.simplesamlphp.org/O=SimpleSAMLphp HQ/L=Honolulu/ST=Hawaii/C=US + + originator + + + testkey + + MIICxDCCAi2gAwIBAgIUZ9QDx+SBFHednUWDFGm9tyVKrgQwDQYJKoZIhvcNAQELBQAwczElMCMGA1UEAwwcc2VsZnNpZ25lZC5zaW1wbGVzYW1scGhwLm9yZzEZMBcGA1UECgwQU2ltcGxlU0FNTHBocCBIUTERMA8GA1UEBwwISG9ub2x1bHUxDzANBgNVBAgMBkhhd2FpaTELMAkGA1UEBhMCVVMwIBcNMjIxMjAzMTAzNTQwWhgPMjEyMjExMDkxMDM1NDBaMHMxJTAjBgNVBAMMHHNlbGZzaWduZWQuc2ltcGxlc2FtbHBocC5vcmcxGTAXBgNVBAoMEFNpbXBsZVNBTUxwaHAgSFExETAPBgNVBAcMCEhvbm9sdWx1MQ8wDQYDVQQIDAZIYXdhaWkxCzAJBgNVBAYTAlVTMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDessdFRVDTMQQW3Na81B1CjJV1tmY3nopoIhZrkbDxLa+pv7jGDRcYreyu1DoQxEs06V2nHLoyOPhqJXSFivqtUwVYhR6NYgbNI6RRSsIJCweH0YOdlHna7gULPcLX0Bfbi4odStaFwG9yzDySwSEPtsKxm5pENPjNVGh+jJ+H/QIDAQABo1MwUTAdBgNVHQ4EFgQUvV75t8EoQo2fVa0E9otdtIGK5X0wHwYDVR0jBBgwFoAUvV75t8EoQo2fVa0E9otdtIGK5X0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQANQUeiwPJXkWMXuaDHToEBKcezYGqGEYnGUi9LMjeb+Kln7X8nn5iknlz4k77rWCbSwLPC/WDr0ySYQA+HagaeUaFpoiYFJKS6uFlK1HYWnM3W4PUiGHg1/xeZlMO44wTwybXVo0y9KMhchfB5XNbDdoJcqWYvi6xtmZZNRbxUyw== + /CN=selfsigned.simplesamlphp.org/O=SimpleSAMLphp HQ/L=Honolulu/ST=Hawaii/C=US + + recipient + + 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= + diff --git a/tests/resources/xml/xenc_Generator.xml b/tests/resources/xml/xenc_Generator.xml new file mode 100644 index 00000000..a87db221 --- /dev/null +++ b/tests/resources/xml/xenc_Generator.xml @@ -0,0 +1 @@ +/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI= diff --git a/tests/resources/xml/xenc_KA-Nonce.xml b/tests/resources/xml/xenc_KA-Nonce.xml new file mode 100644 index 00000000..28552277 --- /dev/null +++ b/tests/resources/xml/xenc_KA-Nonce.xml @@ -0,0 +1 @@ +/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI= diff --git a/tests/resources/xml/xenc_OriginatorKeyInfo.xml b/tests/resources/xml/xenc_OriginatorKeyInfo.xml new file mode 100644 index 00000000..080836d0 --- /dev/null +++ b/tests/resources/xml/xenc_OriginatorKeyInfo.xml @@ -0,0 +1,8 @@ + + testkey + + MIICxDCCAi2gAwIBAgIUZ9QDx+SBFHednUWDFGm9tyVKrgQwDQYJKoZIhvcNAQELBQAwczElMCMGA1UEAwwcc2VsZnNpZ25lZC5zaW1wbGVzYW1scGhwLm9yZzEZMBcGA1UECgwQU2ltcGxlU0FNTHBocCBIUTERMA8GA1UEBwwISG9ub2x1bHUxDzANBgNVBAgMBkhhd2FpaTELMAkGA1UEBhMCVVMwIBcNMjIxMjAzMTAzNTQwWhgPMjEyMjExMDkxMDM1NDBaMHMxJTAjBgNVBAMMHHNlbGZzaWduZWQuc2ltcGxlc2FtbHBocC5vcmcxGTAXBgNVBAoMEFNpbXBsZVNBTUxwaHAgSFExETAPBgNVBAcMCEhvbm9sdWx1MQ8wDQYDVQQIDAZIYXdhaWkxCzAJBgNVBAYTAlVTMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDessdFRVDTMQQW3Na81B1CjJV1tmY3nopoIhZrkbDxLa+pv7jGDRcYreyu1DoQxEs06V2nHLoyOPhqJXSFivqtUwVYhR6NYgbNI6RRSsIJCweH0YOdlHna7gULPcLX0Bfbi4odStaFwG9yzDySwSEPtsKxm5pENPjNVGh+jJ+H/QIDAQABo1MwUTAdBgNVHQ4EFgQUvV75t8EoQo2fVa0E9otdtIGK5X0wHwYDVR0jBBgwFoAUvV75t8EoQo2fVa0E9otdtIGK5X0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQANQUeiwPJXkWMXuaDHToEBKcezYGqGEYnGUi9LMjeb+Kln7X8nn5iknlz4k77rWCbSwLPC/WDr0ySYQA+HagaeUaFpoiYFJKS6uFlK1HYWnM3W4PUiGHg1/xeZlMO44wTwybXVo0y9KMhchfB5XNbDdoJcqWYvi6xtmZZNRbxUyw== + /CN=selfsigned.simplesamlphp.org/O=SimpleSAMLphp HQ/L=Honolulu/ST=Hawaii/C=US + + some + diff --git a/tests/resources/xml/xenc_P.xml b/tests/resources/xml/xenc_P.xml new file mode 100644 index 00000000..9c7ff0e6 --- /dev/null +++ b/tests/resources/xml/xenc_P.xml @@ -0,0 +1 @@ +/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI= diff --git a/tests/resources/xml/xenc_Public.xml b/tests/resources/xml/xenc_Public.xml new file mode 100644 index 00000000..55f5b592 --- /dev/null +++ b/tests/resources/xml/xenc_Public.xml @@ -0,0 +1 @@ +/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI= diff --git a/tests/resources/xml/xenc_Q.xml b/tests/resources/xml/xenc_Q.xml new file mode 100644 index 00000000..421da4f6 --- /dev/null +++ b/tests/resources/xml/xenc_Q.xml @@ -0,0 +1 @@ +/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI= diff --git a/tests/resources/xml/xenc_RecipientKeyInfo.xml b/tests/resources/xml/xenc_RecipientKeyInfo.xml new file mode 100644 index 00000000..bee00ede --- /dev/null +++ b/tests/resources/xml/xenc_RecipientKeyInfo.xml @@ -0,0 +1,8 @@ + + testkey + + MIICxDCCAi2gAwIBAgIUZ9QDx+SBFHednUWDFGm9tyVKrgQwDQYJKoZIhvcNAQELBQAwczElMCMGA1UEAwwcc2VsZnNpZ25lZC5zaW1wbGVzYW1scGhwLm9yZzEZMBcGA1UECgwQU2ltcGxlU0FNTHBocCBIUTERMA8GA1UEBwwISG9ub2x1bHUxDzANBgNVBAgMBkhhd2FpaTELMAkGA1UEBhMCVVMwIBcNMjIxMjAzMTAzNTQwWhgPMjEyMjExMDkxMDM1NDBaMHMxJTAjBgNVBAMMHHNlbGZzaWduZWQuc2ltcGxlc2FtbHBocC5vcmcxGTAXBgNVBAoMEFNpbXBsZVNBTUxwaHAgSFExETAPBgNVBAcMCEhvbm9sdWx1MQ8wDQYDVQQIDAZIYXdhaWkxCzAJBgNVBAYTAlVTMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDessdFRVDTMQQW3Na81B1CjJV1tmY3nopoIhZrkbDxLa+pv7jGDRcYreyu1DoQxEs06V2nHLoyOPhqJXSFivqtUwVYhR6NYgbNI6RRSsIJCweH0YOdlHna7gULPcLX0Bfbi4odStaFwG9yzDySwSEPtsKxm5pENPjNVGh+jJ+H/QIDAQABo1MwUTAdBgNVHQ4EFgQUvV75t8EoQo2fVa0E9otdtIGK5X0wHwYDVR0jBBgwFoAUvV75t8EoQo2fVa0E9otdtIGK5X0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQANQUeiwPJXkWMXuaDHToEBKcezYGqGEYnGUi9LMjeb+Kln7X8nn5iknlz4k77rWCbSwLPC/WDr0ySYQA+HagaeUaFpoiYFJKS6uFlK1HYWnM3W4PUiGHg1/xeZlMO44wTwybXVo0y9KMhchfB5XNbDdoJcqWYvi6xtmZZNRbxUyw== + /CN=selfsigned.simplesamlphp.org/O=SimpleSAMLphp HQ/L=Honolulu/ST=Hawaii/C=US + + some + diff --git a/tests/resources/xml/xenc_pgenCounter.xml b/tests/resources/xml/xenc_pgenCounter.xml new file mode 100644 index 00000000..f56ccdd4 --- /dev/null +++ b/tests/resources/xml/xenc_pgenCounter.xml @@ -0,0 +1 @@ +/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI= diff --git a/tests/resources/xml/xenc_seed.xml b/tests/resources/xml/xenc_seed.xml new file mode 100644 index 00000000..019a5caf --- /dev/null +++ b/tests/resources/xml/xenc_seed.xml @@ -0,0 +1 @@ +/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI=