Skip to content

Commit 43d17aa

Browse files
committed
Move SignedElementTestTrait
1 parent c8dde13 commit 43d17aa

File tree

1 file changed

+189
-0
lines changed

1 file changed

+189
-0
lines changed
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\XMLSecurity\TestUtils;
6+
7+
use DOMDocument;
8+
use Exception;
9+
use SimpleSAML\XMLSecurity\Alg\Signature\SignatureAlgorithmFactory;
10+
use SimpleSAML\XMLSecurity\Constants as C;
11+
use SimpleSAML\XMLSecurity\Exception\InvalidArgumentException;
12+
use SimpleSAML\XMLSecurity\Exception\NoSignatureFoundException;
13+
use SimpleSAML\XMLSecurity\Exception\SignatureVerificationFailedException;
14+
use SimpleSAML\XMLSecurity\Exception\UnsupportedAlgorithmException;
15+
use SimpleSAML\XMLSecurity\Key\PrivateKey;
16+
use SimpleSAML\XMLSecurity\Key\X509Certificate as X509;
17+
use SimpleSAML\XMLSecurity\XML\ds\KeyInfo;
18+
use SimpleSAML\XMLSecurity\XML\ds\X509Certificate;
19+
use SimpleSAML\XMLSecurity\XML\ds\X509Data;
20+
use SimpleSAML\XMLSecurity\TestUtils\PEMCertificatesMock;
21+
use SimpleSAML\XMLSecurity\Utils\Certificate as CertificateUtils;
22+
23+
use function array_keys;
24+
use function boolval;
25+
use function class_exists;
26+
use function hexdec;
27+
use function sprintf;
28+
29+
/**
30+
* A trait providing basic tests for signed elements.
31+
*
32+
* Only to be used by classes extending \PHPUnit\Framework\TestCase. Make sure to assign the class name of the class
33+
* you are testing to the $testedClass property.
34+
*
35+
* @package simplesamlphp/xml-security
36+
*/
37+
trait SignedElementTestTrait
38+
{
39+
/**
40+
* A base document that we can reuse in our tests.
41+
*
42+
* @var \DOMDocument
43+
*/
44+
protected DOMDocument $xmlRepresentation;
45+
46+
/**
47+
* The name of the class we are testing.
48+
*
49+
* @var class-string
50+
*/
51+
protected string $testedClass;
52+
53+
54+
/**
55+
* Test signing / verifying
56+
*/
57+
public function testSignatures(): void
58+
{
59+
if (!class_exists($this->testedClass)) {
60+
$this->markTestSkipped(
61+
'Unable to run ' . self::class . '::testSignatures(). Please set ' . self::class
62+
. ':$testedClass to a class-string representing the XML-class being tested',
63+
);
64+
} elseif (empty($this->xmlRepresentation)) {
65+
$this->markTestSkipped(
66+
'Unable to run ' . self::class . '::testSignatures(). Please set ' . self::class
67+
. ':$xmlRepresentation to a DOMDocument representing the XML-class being tested',
68+
);
69+
} else {
70+
/** @psalm-var class-string|null */
71+
$testedClass = $this->testedClass;
72+
73+
/** @psalm-var \DOMElement|null */
74+
$xmlRepresentation = $this->xmlRepresentation;
75+
76+
$algorithms = array_keys(C::$RSA_DIGESTS);
77+
foreach ($algorithms as $algorithm) {
78+
if (
79+
boolval(OPENSSL_VERSION_NUMBER >= hexdec('0x30000000')) === true
80+
&& ($algorithm === C::SIG_RSA_SHA1 || $algorithm === C::SIG_RSA_RIPEMD160)
81+
) {
82+
// OpenSSL 3.0 disabled SHA1 and RIPEMD160 support
83+
continue;
84+
}
85+
86+
//
87+
// sign with two certificates
88+
//
89+
$signer = (new SignatureAlgorithmFactory([]))->getAlgorithm(
90+
$algorithm,
91+
PEMCertificatesMock::getPrivateKey(PEMCertificatesMock::PRIVATE_KEY),
92+
);
93+
94+
$keyInfo = new KeyInfo([
95+
new X509Data([new X509Certificate(
96+
PEMCertificatesMock::getPlainPublicKeyContents(PEMCertificatesMock::PUBLIC_KEY),
97+
)]),
98+
new X509Data([new X509Certificate(
99+
PEMCertificatesMock::getPlainPublicKeyContents(PEMCertificatesMock::OTHER_PUBLIC_KEY),
100+
)]),
101+
]);
102+
103+
$unsigned = $testedClass::fromXML($xmlRepresentation->documentElement);
104+
$unsigned->sign($signer, C::C14N_EXCLUSIVE_WITHOUT_COMMENTS, $keyInfo);
105+
$signed = $this->testedClass::fromXML($unsigned->toXML());
106+
$this->assertEquals(
107+
$algorithm,
108+
$signed->getSignature()->getSignedInfo()->getSignatureMethod()->getAlgorithm(),
109+
);
110+
111+
// verify signature
112+
$verifier = (new SignatureAlgorithmFactory([]))->getAlgorithm(
113+
$signed->getSignature()->getSignedInfo()->getSignatureMethod()->getAlgorithm(),
114+
PEMCertificatesMock::getPublicKey(PEMCertificatesMock::PUBLIC_KEY),
115+
);
116+
117+
try {
118+
$verified = $signed->verify($verifier);
119+
} catch (
120+
NoSignatureFoundException |
121+
InvalidArgumentException |
122+
SignatureVerificationFailedException $s
123+
) {
124+
$this->fail(sprintf('%s: %s', $algorithm, $e->getMessage()));
125+
}
126+
$this->assertInstanceOf($this->testedClass, $verified);
127+
128+
$this->assertEquals(
129+
PEMCertificatesMock::getPublicKey(PEMCertificatesMock::PUBLIC_KEY),
130+
$verified->getVerifyingKey(),
131+
sprintf('No validating certificate for algorithm: %s', $algorithm),
132+
);
133+
134+
//
135+
// sign without certificates
136+
//
137+
$unsigned->sign($signer, C::C14N_EXCLUSIVE_WITHOUT_COMMENTS, null);
138+
$signed = $this->testedClass::fromXML($unsigned->toXML());
139+
140+
// verify signature
141+
try {
142+
$verified = $signed->verify($verifier);
143+
} catch (
144+
NoSignatureFoundException |
145+
InvalidArgumentException |
146+
SignatureVerificationFailedException $e
147+
) {
148+
$this->fail(sprintf('%s: %s', $algorithm, $e->getMessage()));
149+
}
150+
$this->assertInstanceOf($this->testedClass, $verified);
151+
152+
$this->assertEquals(
153+
PEMCertificatesMock::getPublicKey(PEMCertificatesMock::PUBLIC_KEY),
154+
$verified->getVerifyingKey(),
155+
sprintf('No validating certificate for algorithm: %s', $algorithm),
156+
);
157+
158+
//
159+
// verify with wrong key
160+
//
161+
$signer = (new SignatureAlgorithmFactory([]))->getAlgorithm(
162+
$algorithm,
163+
PEMCertificatesMock::getPrivateKey(PEMCertificatesMock::OTHER_PRIVATE_KEY),
164+
);
165+
$unsigned->sign($signer, C::C14N_EXCLUSIVE_WITHOUT_COMMENTS, null);
166+
$signed = $this->testedClass::fromXML($unsigned->toXML());
167+
168+
// verify signature
169+
try {
170+
$verified = $signed->verify($verifier);
171+
$this->fail('Signature validated correctly with wrong certificate.');
172+
} catch (
173+
NoSignatureFoundException |
174+
InvalidArgumentException |
175+
SignatureVerificationFailedException $e
176+
) {
177+
$this->assertEquals('Failed to verify signature.', $e->getMessage());
178+
}
179+
$this->assertInstanceOf($this->testedClass, $verified);
180+
181+
$this->assertEquals(
182+
PEMCertificatesMock::getPublicKey(PEMCertificatesMock::PUBLIC_KEY),
183+
$verified->getVerifyingKey(),
184+
sprintf('No validating certificate for algorithm: %s', $algorithm),
185+
);
186+
}
187+
}
188+
}
189+
}

0 commit comments

Comments
 (0)