-
Notifications
You must be signed in to change notification settings - Fork 138
Expand file tree
/
Copy pathSignableElementTrait.php
More file actions
142 lines (123 loc) · 5.02 KB
/
Copy pathSignableElementTrait.php
File metadata and controls
142 lines (123 loc) · 5.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
<?php
declare(strict_types=1);
namespace SimpleSAML\SAML2\XML;
use Dom;
use SimpleSAML\SAML2\Assert\Assert;
use SimpleSAML\SAML2\Compat\ContainerSingleton;
use SimpleSAML\XML\DOMDocumentFactory;
use SimpleSAML\XMLSchema\Type\AnyURIValue;
use SimpleSAML\XMLSchema\Type\Base64BinaryValue;
use SimpleSAML\XMLSecurity\Alg\Signature\SignatureAlgorithmInterface;
use SimpleSAML\XMLSecurity\Constants as C;
use SimpleSAML\XMLSecurity\Exception\RuntimeException;
use SimpleSAML\XMLSecurity\Exception\UnsupportedAlgorithmException;
use SimpleSAML\XMLSecurity\XML\ds\CanonicalizationMethod;
use SimpleSAML\XMLSecurity\XML\ds\KeyInfo;
use SimpleSAML\XMLSecurity\XML\ds\Signature;
use SimpleSAML\XMLSecurity\XML\ds\SignatureMethod;
use SimpleSAML\XMLSecurity\XML\ds\SignatureValue;
use SimpleSAML\XMLSecurity\XML\ds\SignedInfo;
use SimpleSAML\XMLSecurity\XML\ds\Transform;
use SimpleSAML\XMLSecurity\XML\ds\Transforms;
use SimpleSAML\XMLSecurity\XML\SignableElementTrait as BaseSignableElementTrait;
use function base64_encode;
/**
* Helper trait for processing signable elements.
*
* @package simplesamlphp/saml2
*/
trait SignableElementTrait
{
use BaseSignableElementTrait;
/**
* Sign the current element.
*
* The signature will not be applied until toXML() is called.
*
* @param \SimpleSAML\XMLSecurity\Alg\Signature\SignatureAlgorithmInterface $signer The actual signer implementation
* to use.
* @param string $canonicalizationAlg The identifier of the canonicalization algorithm to use.
* @param \SimpleSAML\XMLSecurity\XML\ds\KeyInfo|null $keyInfo A KeyInfo object to add to the signature.
*/
public function sign(
SignatureAlgorithmInterface $signer,
string $canonicalizationAlg = C::C14N_EXCLUSIVE_WITHOUT_COMMENTS,
?KeyInfo $keyInfo = null,
): void {
/**
* 5.4.2: SAML assertions and protocol messages MUST supply a value for the ID attribute
* on the root element of the assertion or protocol message being signed.
*/
Assert::notNull($this->getID(), "Signable element must have an ID set before it can be signed.");
$this->signer = $signer;
$this->keyInfo = $keyInfo;
Assert::oneOf(
$canonicalizationAlg,
[
C::C14N_EXCLUSIVE_WITH_COMMENTS,
C::C14N_EXCLUSIVE_WITHOUT_COMMENTS,
],
'Unsupported canonicalization algorithm: %s',
UnsupportedAlgorithmException::class,
);
$this->c14nAlg = $canonicalizationAlg;
}
/**
* Do the actual signing of the document.
*
* Note that this method does not insert the signature in the returned \Dom\Element. The signature will be available
* in $this->signature as a \SimpleSAML\XMLSecurity\XML\ds\Signature object, which can then be converted to XML
* calling toXML() on it, passing the \Dom\Element value returned here as a parameter. The resulting \Dom\Element
* can then be inserted in the position desired.
*
* E.g.:
* $xml = // our XML to sign
* $signedXML = $this->doSign($xml);
* $signedXML->appendChild($this->signature->toXML($signedXML));
*
* @param \Dom\Element $xml The element to sign.
* @return \Dom\Element The signed element, without the signature attached to it just yet.
*/
protected function doSign(Dom\Element $xml): Dom\Element
{
Assert::notNull(
$this->signer,
'Cannot call toSignedXML() without calling sign() first.',
RuntimeException::class,
);
$algorithm = $this->signer->getAlgorithmId();
$digest = $this->signer->getDigest();
$transforms = new Transforms([
/**
* 5.4.1: SAML assertions and protocols MUST use enveloped signatures when
* signing assertions and protocol messages
*/
new Transform(AnyURIValue::fromString(C::XMLDSIG_ENVELOPED)),
new Transform(AnyURIValue::fromString($this->c14nAlg)),
]);
$canonicalDocument = $this->processTransforms($transforms, $xml);
$signedInfo = new SignedInfo(
new CanonicalizationMethod(AnyURIValue::fromString($this->c14nAlg)),
new SignatureMethod(AnyURIValue::fromString($algorithm)),
[$this->getReference($digest, $transforms, $xml, $canonicalDocument)],
);
$signingData = $signedInfo->canonicalize($this->c14nAlg);
$signedData = base64_encode($this->signer->sign($signingData));
$this->signature = new Signature(
$signedInfo,
new SignatureValue(
Base64BinaryValue::fromString($signedData),
),
$this->keyInfo,
);
return DOMDocumentFactory::fromString($canonicalDocument)->documentElement;
}
/**
* @return array|null
*/
public function getBlacklistedAlgorithms(): ?array
{
$container = ContainerSingleton::getInstance();
return $container->getBlacklistedEncryptionAlgorithms();
}
}