Skip to content

Commit ba8c751

Browse files
authored
Add XML-implementation for ds:X509IssuerSerial (#8)
* Add XML-representation for ds:X509IssuerSerial element * Add XML-representation for ds:X509SerialNumber element * Add XML-representation for ds:X509IssuerName element * Implement X509IssuerName
1 parent ed87a96 commit ba8c751

12 files changed

Lines changed: 634 additions & 4 deletions

src/Utils/Certificate.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,23 @@ public static function convertToCertificate(string $X509CertificateContents): st
3737
. chunk_split($X509CertificateContents, 64, "\n")
3838
. "-----END CERTIFICATE-----";
3939
}
40+
41+
42+
/**
43+
* @param array|string $issuer
44+
*
45+
* @return string
46+
*/
47+
public static function parseIssuer($issuer): string
48+
{
49+
if (is_array($issuer)) {
50+
$parts = [];
51+
foreach ($issuer as $key => $value) {
52+
array_unshift($parts, $key . '=' . $value);
53+
}
54+
return implode(',', $parts);
55+
}
56+
57+
return $issuer;
58+
}
4059
}

src/XML/ds/X509IssuerName.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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+
11+
/**
12+
* Class representing a ds:X509IssuerName element.
13+
*
14+
* @package simplesaml/xml-security
15+
*/
16+
final class X509IssuerName extends AbstractDsElement
17+
{
18+
/**
19+
* The subject name.
20+
*
21+
* @var string
22+
*/
23+
protected string $name;
24+
25+
26+
/**
27+
* Initialize a X509IssuerName element.
28+
*
29+
* @param string $name
30+
*/
31+
public function __construct(string $name)
32+
{
33+
$this->setName($name);
34+
}
35+
36+
37+
/**
38+
* Collect the value of the name-property
39+
*
40+
* @return string
41+
*/
42+
public function getName(): string
43+
{
44+
return $this->name;
45+
}
46+
47+
48+
/**
49+
* Set the value of the name-property
50+
*
51+
* @param string $name
52+
*/
53+
private function setName(string $name): void
54+
{
55+
Assert::notEmpty($name, 'ds:X509IssuerName cannot be empty.');
56+
$this->name = $name;
57+
}
58+
59+
60+
/**
61+
* Convert XML into a X509IssuerName
62+
*
63+
* @param \DOMElement $xml The XML element we should load
64+
* @return self
65+
*
66+
* @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
67+
* If the qualified name of the supplied element is wrong
68+
*/
69+
public static function fromXML(DOMElement $xml): object
70+
{
71+
Assert::same($xml->localName, 'X509IssuerName', InvalidDOMElementException::class);
72+
Assert::same($xml->namespaceURI, X509IssuerName::NS, InvalidDOMElementException::class);
73+
74+
return new self($xml->textContent);
75+
}
76+
77+
78+
/**
79+
* Convert this X509IssuerName element to XML.
80+
*
81+
* @param \DOMElement|null $parent The element we should append this X509IssuerName element to.
82+
* @return \DOMElement
83+
*/
84+
public function toXML(DOMElement $parent = null): DOMElement
85+
{
86+
$e = $this->instantiateParentElement($parent);
87+
$e->textContent = $this->name;
88+
89+
return $e;
90+
}
91+
}

src/XML/ds/X509IssuerSerial.php

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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\Constants;
10+
use SimpleSAML\XML\Exception\InvalidDOMElementException;
11+
use SimpleSAML\XML\Exception\MissingElementException;
12+
use SimpleSAML\XML\Exception\TooManyElementsException;
13+
use SimpleSAML\XML\Utils as XMLUtils;
14+
15+
/**
16+
* Class representing a ds:X509IssuerSerial element.
17+
*
18+
* @package simplesaml/xml-security
19+
*/
20+
final class X509IssuerSerial extends AbstractDsElement
21+
{
22+
/**
23+
* The Issuer's name.
24+
*
25+
* @var \SimpleSAML\XMLSecurity\XML\ds\X509IssuerName
26+
*/
27+
protected X509IssuerName $X509IssuerName;
28+
29+
/**
30+
* The serial number.
31+
*
32+
* @var \SimpleSAML\XMLSecurity\XML\ds\X509SerialNumber
33+
*/
34+
protected X509SerialNumber $X509SerialNumber;
35+
36+
37+
/**
38+
* Initialize a X509SubjectName element.
39+
*
40+
* @param \SimpleSAML\XMLSecurity\XML\ds\X509IssuerName $name
41+
* @param \SimpleSAML\XMLSecurity\XML\ds\X509SerialNumber $serial
42+
*/
43+
public function __construct(X509IssuerName $name, X509SerialNumber $serial)
44+
{
45+
$this->setIssuerName($name);
46+
$this->setSerialNumber($serial);
47+
}
48+
49+
50+
/**
51+
* Collect the value of the X509IssuerName-property
52+
*
53+
* @return \SimpleSAML\XMLSecurity\XML\ds\X509IssuerName
54+
*/
55+
public function getIssuerName(): X509IssuerName
56+
{
57+
return $this->X509IssuerName;
58+
}
59+
60+
61+
/**
62+
* Set the value of the X509IssuerName-property
63+
*
64+
* @param \SimpleSAML\XMLSecurity\XML\ds\X509IssuerName $name
65+
*/
66+
private function setIssuerName(X509IssuerName $name): void
67+
{
68+
$this->X509IssuerName = $name;
69+
}
70+
71+
72+
/**
73+
* Collect the value of the X509SerialNumber-property
74+
*
75+
* @return \SimpleSAML\XMLSecurity\XML\ds\X509SerialNumber
76+
*/
77+
public function getSerialNumber(): X509SerialNumber
78+
{
79+
return $this->X509SerialNumber;
80+
}
81+
82+
83+
/**
84+
* Set the value of the X509SerialNumber-property
85+
*
86+
* @param \SimpleSAML\XMLSecurity\XML\ds\X509SerialNumber $serial
87+
*/
88+
private function setSerialNumber(X509SerialNumber $serial): void
89+
{
90+
$this->X509SerialNumber = $serial;
91+
}
92+
93+
94+
/**
95+
* Convert XML into a X509IssuerSerial
96+
*
97+
* @param \DOMElement $xml The XML element we should load
98+
* @return self
99+
*
100+
* @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
101+
* If the qualified name of the supplied element is wrong
102+
*/
103+
public static function fromXML(DOMElement $xml): object
104+
{
105+
Assert::same($xml->localName, 'X509IssuerSerial', InvalidDOMElementException::class);
106+
Assert::same($xml->namespaceURI, X509IssuerSerial::NS, InvalidDOMElementException::class);
107+
108+
$issuer = X509IssuerName::getChildrenOfClass($xml);
109+
$serial = X509SerialNumber::getChildrenOfClass($xml);
110+
111+
Assert::minCount($issuer, 1, MissingElementException::class);
112+
Assert::maxCount($issuer, 1, TooManyElementsException::class);
113+
114+
Assert::minCount($serial, 1, MissingElementException::class);
115+
Assert::maxCount($serial, 1, TooManyElementsException::class);
116+
117+
return new self(
118+
array_pop($issuer),
119+
array_pop($serial)
120+
);
121+
}
122+
123+
124+
/**
125+
* Convert this X509IssuerSerial element to XML.
126+
*
127+
* @param \DOMElement|null $parent The element we should append this X509IssuerSerial element to.
128+
* @return \DOMElement
129+
*/
130+
public function toXML(DOMElement $parent = null): DOMElement
131+
{
132+
$e = $this->instantiateParentElement($parent);
133+
134+
$this->X509IssuerName->toXML($e);
135+
$this->X509SerialNumber->toXML($e);
136+
137+
return $e;
138+
}
139+
}

src/XML/ds/X509SerialNumber.php

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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\Constants;
10+
use SimpleSAML\XML\Exception\InvalidDOMElementException;
11+
12+
/**
13+
* Class representing a ds:X509SerialNumber element.
14+
*
15+
* @package simplesaml/xml-security
16+
*/
17+
final class X509SerialNumber extends AbstractDsElement
18+
{
19+
/**
20+
* The serial number.
21+
*
22+
* @var int
23+
*/
24+
protected int $serial;
25+
26+
27+
/**
28+
* Initialize a X509SerialNumber element.
29+
*
30+
* @param int $serial
31+
*/
32+
public function __construct(int $serial)
33+
{
34+
$this->setSerial($serial);
35+
}
36+
37+
38+
/**
39+
* Collect the value of the serial-property
40+
*
41+
* @return int
42+
*/
43+
public function getSerial(): int
44+
{
45+
return $this->serial;
46+
}
47+
48+
49+
/**
50+
* Set the value of the serial-property
51+
*
52+
* @param int $serial
53+
*/
54+
private function setSerial(int $serial): void
55+
{
56+
$this->serial = $serial;
57+
}
58+
59+
60+
/**
61+
* Convert XML into a X509SerialNumber
62+
*
63+
* @param \DOMElement $xml The XML element we should load
64+
* @return self
65+
*
66+
* @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
67+
* If the qualified name of the supplied element is wrong
68+
*/
69+
public static function fromXML(DOMElement $xml): object
70+
{
71+
Assert::same($xml->localName, 'X509SerialNumber', InvalidDOMElementException::class);
72+
Assert::same($xml->namespaceURI, X509SerialNumber::NS, InvalidDOMElementException::class);
73+
Assert::same($xml->getAttributeNS(Constants::NS_XSI, "type"), 'xs:integer');
74+
75+
return new self(intval($xml->textContent));
76+
}
77+
78+
79+
/**
80+
* Convert this X509SerialNumber element to XML.
81+
*
82+
* @param \DOMElement|null $parent The element we should append this X509SerialNumber element to.
83+
* @return \DOMElement
84+
*/
85+
public function toXML(DOMElement $parent = null): DOMElement
86+
{
87+
$e = $this->instantiateParentElement($parent);
88+
89+
$e->setAttributeNS(Constants::NS_XSI, 'xsi:type', 'xs:integer');
90+
$e->textContent = strval($this->serial);
91+
92+
return $e;
93+
}
94+
}

tests/Utils/CertificateTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public function testValidStructure(): void
2424
PEMCertificatesMock::getPlainPublicKey(PEMCertificatesMock::PUBLIC_KEY)
2525
);
2626
$this->assertTrue($result);
27+
2728
$result = Certificate::hasValidStructure(
2829
PEMCertificatesMock::getPlainPublicKey(PEMCertificatesMock::BROKEN_PUBLIC_KEY)
2930
);
@@ -41,4 +42,26 @@ public function testConvertToCertificate(): void
4142
// the formatted public key in PEMCertificatesMock is stored with unix newlines
4243
$this->assertEquals(trim(PEMCertificatesMock::getPlainPublicKey()), $result);
4344
}
45+
46+
47+
/**
48+
*/
49+
public function testParseIssuer(): void
50+
{
51+
// Test string input
52+
$result = Certificate::parseIssuer('test');
53+
$this->assertEquals('test', $result);
54+
55+
// Test array input
56+
$result = Certificate::parseIssuer(
57+
[
58+
'C' => 'US',
59+
'S' => 'Hawaii',
60+
'L' => 'Honolulu',
61+
'O' => 'SimpleSAMLphp HQ',
62+
'CN' => 'SimpleSAMLphp Testing CA',
63+
]
64+
);
65+
$this->assertEquals('CN=SimpleSAMLphp Testing CA,O=SimpleSAMLphp HQ,L=Honolulu,S=Hawaii,C=US', $result);
66+
}
4467
}

0 commit comments

Comments
 (0)