Skip to content

Commit 17ebf55

Browse files
authored
Add implementation for ds:SignedInfo (#16)
* Add ds:SignedInfo element
1 parent b5ce290 commit 17ebf55

3 files changed

Lines changed: 310 additions & 0 deletions

File tree

src/XML/ds/SignedInfo.php

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\XMLSecurity\XML\ds;
6+
7+
use DOMElement;
8+
use SimpleSAML\Assert\Assert;
9+
use SimpleSAML\XML\Exception\InvalidDOMElementException;
10+
use SimpleSAML\XML\Chunk;
11+
12+
/**
13+
* Class representing a ds:SignedInfo element.
14+
*
15+
* @package simplesamlphp/xml-security
16+
*/
17+
final class SignedInfo extends AbstractDsElement
18+
{
19+
/** @var string */
20+
protected string $Id;
21+
22+
/**
23+
* @var \SimpleSAML\XMLSecurity\XML\ds\CanonicalizationMethod
24+
*/
25+
protected CanonicalizationMethod $canonicalizationMethod;
26+
27+
/**
28+
* @var \SimpleSAML\XMLSecurity\XML\ds\SignatureMethod
29+
*/
30+
protected SignatureMethod $signatureMethod;
31+
32+
/**
33+
* @var \SimpleSAML\XMLSecurity\XML\ds\Reference[]
34+
*/
35+
protected array $references;
36+
37+
38+
/**
39+
* Initialize a SignedIfno.
40+
*
41+
* @param \SimpleSAML\XMLSecurity\XML\ds\CanonicalizationMethod $canonicalizationMethod
42+
* @param \SimpleSAML\XMLSecurity\XML\ds\SignatureMethod $signatureMethod
43+
* @param \SimpleSAML\XMLSecurity\XML\ds\Reference[] $references
44+
* @param string|null $Id
45+
*/
46+
public function __construct(
47+
CanonicalizationMethod $canonicalizationMethod,
48+
SignatureMethod $signatureMethod,
49+
array $references,
50+
?string $Id = null
51+
) {
52+
$this->setCanonicalizationMethod($canonicalizationMethod);
53+
$this->setSignatureMethod($signatureMethod);
54+
$this->setReferences($references);
55+
$this->setId($Id);
56+
}
57+
58+
59+
/**
60+
* Collect the value of the canonicalizationMethod-property
61+
*
62+
* @return \SimpleSAML\XMLSecurity\XML\ds\CanonicalizationMethod
63+
*/
64+
public function getCanonicalizationMethod(): CanonicalizationMethod
65+
{
66+
return $this->canonicalizationMethod;
67+
}
68+
69+
70+
/**
71+
* Set the value of the canonicalizationMethod-property
72+
*
73+
* @param \SimpleSAML\XMLSecurity\XML\ds\CanonicalizationMethod $canonicalizationMethod
74+
*/
75+
private function setCanonicalizationMethod(CanonicalizationMethod $canonicalizationMethod): void
76+
{
77+
$this->canonicalizationMethod = $canonicalizationMethod;
78+
}
79+
80+
81+
/**
82+
* Collect the value of the signatureMethod-property
83+
*
84+
* @return \SimpleSAML\XMLSecurity\XML\ds\SignatureMethod
85+
*/
86+
public function getSignatureMethod(): SignatureMethod
87+
{
88+
return $this->signatureMethod;
89+
}
90+
91+
92+
/**
93+
* Set the value of the signatureMethod-property
94+
*
95+
* @param \SimpleSAML\XMLSecurity\XML\ds\SignatureMethod $signatureMethod
96+
*/
97+
private function setSignatureMethod(SignatureMethod $signatureMethod): void
98+
{
99+
$this->signatureMethod = $signatureMethod;
100+
}
101+
102+
103+
/**
104+
* Collect the value of the references-property
105+
*
106+
* @return \SimpleSAML\XMLSecurity\XML\ds\Reference[]
107+
*/
108+
public function getReferences(): array
109+
{
110+
return $this->references;
111+
}
112+
113+
114+
/**
115+
* Set the value of the references-property
116+
*
117+
* @param \SimpleSAML\XMLSecurity\XML\ds\Reference[] $references
118+
*/
119+
private function setReferences(array $references): void
120+
{
121+
Assert::allIsInstanceOf($references, Reference::class);
122+
123+
$this->references = $references;
124+
}
125+
126+
127+
/**
128+
* Collect the value of the Id-property
129+
*
130+
* @return string|null
131+
*/
132+
public function getId(): ?string
133+
{
134+
return $this->Id;
135+
}
136+
137+
138+
/**
139+
* Set the value of the Id-property
140+
*
141+
* @param string|null $Id
142+
*/
143+
private function setId(?string $Id): void
144+
{
145+
$this->Id = $Id;
146+
}
147+
148+
149+
/**
150+
* Convert XML into a SignedInfo instance
151+
*
152+
* @param \DOMElement $xml The XML element we should load
153+
* @return self
154+
*
155+
* @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
156+
* If the qualified name of the supplied element is wrong
157+
*/
158+
public static function fromXML(DOMElement $xml): object
159+
{
160+
Assert::same($xml->localName, 'SignedInfo', InvalidDOMElementException::class);
161+
Assert::same($xml->namespaceURI, SignedInfo::NS, InvalidDOMElementException::class);
162+
163+
$Id = self::getAttribute($xml, 'Id', null);
164+
165+
$canonicalizationMethod = CanonicalizationMethod::getChildrenOfClass($xml);
166+
Assert::count($canonicalizationMethod, 1, 'A ds:SignedInfo element must contain exactly one ds:CanonicalizationMethod');
167+
168+
$signatureMethod = SignatureMethod::getChildrenOfClass($xml);
169+
Assert::count($signatureMethod, 1, 'A ds:SignedInfo element must contain exactly one ds:SignatureMethod');
170+
171+
$references = Reference::getChildrenOfClass($xml);
172+
Assert::minCount($references, 1, 'A ds:SignedInfo element must contain at least one ds:Reference');
173+
174+
return new self(
175+
array_pop($canonicalizationMethod),
176+
array_pop($signatureMethod),
177+
$references,
178+
$Id
179+
);
180+
}
181+
182+
183+
/**
184+
* Convert this SignedInfo element to XML.
185+
*
186+
* @param \DOMElement|null $parent The element we should append this SignedInfo element to.
187+
* @return \DOMElement
188+
*/
189+
public function toXML(DOMElement $parent = null): DOMElement
190+
{
191+
$e = $this->instantiateParentElement($parent);
192+
193+
if ($this->Id !== null) {
194+
$e->setAttribute('Id', $this->Id);
195+
}
196+
197+
$this->canonicalizationMethod->toXML($e);
198+
$this->signatureMethod->toXML($e);
199+
200+
foreach ($this->references as $ref) {
201+
$ref->toXML($e);
202+
}
203+
204+
return $e;
205+
}
206+
}

tests/XML/ds/SignedInfoTest.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\XMLSecurity\Test\XML\ds;
6+
7+
use DOMDocument;
8+
use PHPUnit\Framework\TestCase;
9+
use SimpleSAML\Test\XML\SerializableXMLTestTrait;
10+
use SimpleSAML\XML\DOMDocumentFactory;
11+
use SimpleSAML\XML\Chunk;
12+
use SimpleSAML\XML\Utils as XMLUtils;
13+
use SimpleSAML\XMLSecurity\Constants;
14+
use SimpleSAML\XMLSecurity\XML\ds\CanonicalizationMethod;
15+
use SimpleSAML\XMLSecurity\XML\ds\Reference;
16+
use SimpleSAML\XMLSecurity\XML\ds\SignatureMethod;
17+
use SimpleSAML\XMLSecurity\XML\ds\SignedInfo;
18+
19+
/**
20+
* Class \SimpleSAML\XMLSecurity\Test\XML\ds\SignedInfoTest
21+
*
22+
* @covers \SimpleSAML\XMLSecurity\XML\ds\SignedInfo
23+
* @covers \SimpleSAML\XMLSecurity\XML\ds\AbstractDsElement
24+
*
25+
* @package simplesamlphp/xml-security
26+
*/
27+
final class SignedInfoTest extends TestCase
28+
{
29+
use SerializableXMLTestTrait;
30+
31+
32+
/**
33+
*/
34+
public function setUp(): void
35+
{
36+
$this->testedClass = SignedInfo::class;
37+
38+
$this->xmlRepresentation = DOMDocumentFactory::fromFile(
39+
dirname(dirname(dirname(__FILE__))) . '/resources/xml/ds_SignedInfo.xml'
40+
);
41+
}
42+
43+
44+
/**
45+
*/
46+
public function testMarshalling(): void
47+
{
48+
$signedInfo = new SignedInfo(
49+
new CanonicalizationMethod(Constants::C14N_EXCLUSIVE_WITHOUT_COMMENTS),
50+
new SignatureMethod(Constants::SIG_RSA_SHA256),
51+
[
52+
Reference::fromXML(
53+
DOMDocumentFactory::fromFile(
54+
dirname(dirname(dirname(__FILE__))) . '/resources/xml/ds_Reference.xml'
55+
)->documentElement
56+
)
57+
],
58+
'abc123'
59+
);
60+
61+
$this->assertEquals(
62+
$this->xmlRepresentation->saveXML($this->xmlRepresentation->documentElement),
63+
strval($signedInfo)
64+
);
65+
}
66+
67+
68+
/**
69+
*/
70+
public function testUnmarshalling(): void
71+
{
72+
$signedInfo = SignedInfo::fromXML($this->xmlRepresentation->documentElement);
73+
$this->assertEquals('abc123', $signedInfo->getId());
74+
75+
$this->assertEquals(
76+
Constants::C14N_EXCLUSIVE_WITHOUT_COMMENTS,
77+
$signedInfo->getCanonicalizationMethod()->getAlgorithm()
78+
);
79+
$this->assertEquals(
80+
Constants::SIG_RSA_SHA256,
81+
$signedInfo->getSignatureMethod()->getAlgorithm()
82+
);
83+
84+
$references = $signedInfo->getReferences();
85+
$this->assertCount(1, $references);
86+
87+
$this->assertEquals(
88+
$this->xmlRepresentation->saveXML($this->xmlRepresentation->documentElement),
89+
strval($signedInfo)
90+
);
91+
}
92+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="abc123">
2+
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
3+
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
4+
<ds:Reference Id="abc123" Type="someType" URI="#_1e280ee704fb1d8d9dec4bd6c1889ec96942921153">
5+
<ds:Transforms>
6+
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
7+
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
8+
</ds:Transforms>
9+
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
10+
<ds:DigestValue>/CTj03d1DB5e2t7CTo9BEzCf5S9NRzwnBgZRlm32REI=</ds:DigestValue>
11+
</ds:Reference>
12+
</ds:SignedInfo>

0 commit comments

Comments
 (0)