Issues (81)

src/XML/xenc/EncryptedKey.php (1 issue)

Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\XMLSecurity\XML\xenc;
6
7
use DOMElement;
8
use SimpleSAML\Assert\Assert;
9
use SimpleSAML\XML\{SchemaValidatableElementInterface, SchemaValidatableElementTrait};
10
use SimpleSAML\XMLSchema\Exception\{InvalidDOMElementException, TooManyElementsException};
11
use SimpleSAML\XMLSchema\Type\{AnyURIValue, Base64BinaryValue, IDValue, StringValue};
12
use SimpleSAML\XMLSecurity\Alg\Encryption\EncryptionAlgorithmInterface;
13
use SimpleSAML\XMLSecurity\Exception\InvalidArgumentException;
14
use SimpleSAML\XMLSecurity\Key\KeyInterface;
15
use SimpleSAML\XMLSecurity\XML\ds\KeyInfo;
16
17
use function strval;
18
19
/**
20
 * Class representing an encrypted key.
21
 *
22
 * @package simplesamlphp/xml-security
23
 */
24
final class EncryptedKey extends AbstractEncryptedType implements SchemaValidatableElementInterface
25
{
26
    use SchemaValidatableElementTrait;
0 ignored issues
show
The trait SimpleSAML\XML\SchemaValidatableElementTrait requires some properties which are not provided by SimpleSAML\XMLSecurity\XML\xenc\EncryptedKey: $message, $line
Loading history...
27
28
    /**
29
     * EncryptedKey constructor.
30
     *
31
     * @param \SimpleSAML\XMLSecurity\XML\xenc\CipherData $cipherData The CipherData object of this EncryptedData.
32
     * @param \SimpleSAML\XMLSchema\Type\IDValue|null $id
33
     *   The Id attribute of this object. Optional.
34
     * @param \SimpleSAML\XMLSchema\Type\AnyURIValue|null $type
35
     *   The Type attribute of this object. Optional.
36
     * @param \SimpleSAML\XMLSchema\Type\StringValue|null $mimeType
37
     *   The MimeType attribute of this object. Optional.
38
     * @param \SimpleSAML\XMLSchema\Type\AnyURIValue|null $encoding
39
     *   The Encoding attribute of this object. Optional.
40
     * @param \SimpleSAML\XMLSchema\Type\StringValue|null $recipient
41
     *   The Recipient attribute of this object. Optional.
42
     * @param \SimpleSAML\XMLSecurity\XML\xenc\CarriedKeyName|null $carriedKeyName
43
     *   The value of the CarriedKeyName element of this EncryptedData.
44
     * @param \SimpleSAML\XMLSecurity\XML\xenc\EncryptionMethod|null $encryptionMethod
45
     *   The EncryptionMethod object of this EncryptedData. Optional.
46
     * @param \SimpleSAML\XMLSecurity\XML\ds\KeyInfo|null $keyInfo The KeyInfo object of this EncryptedData. Optional.
47
     * @param \SimpleSAML\XMLSecurity\XML\xenc\ReferenceList|null $referenceList
48
     *   The ReferenceList object of this EncryptedData. Optional.
49
     */
50
    final public function __construct(
51
        CipherData $cipherData,
52
        ?IDValue $id = null,
53
        ?AnyURIValue $type = null,
54
        ?StringValue $mimeType = null,
55
        ?AnyURIValue $encoding = null,
56
        protected ?StringValue $recipient = null,
57
        protected ?CarriedKeyName $carriedKeyName = null,
58
        ?EncryptionMethod $encryptionMethod = null,
59
        ?KeyInfo $keyInfo = null,
60
        protected ?ReferenceList $referenceList = null,
61
    ) {
62
        parent::__construct($cipherData, $id, $type, $mimeType, $encoding, $encryptionMethod, $keyInfo);
63
    }
64
65
66
    /**
67
     * Get the value of the CarriedKeyName property.
68
     *
69
     * @return \SimpleSAML\XMLSecurity\XML\xenc\CarriedKeyName|null
70
     */
71
    public function getCarriedKeyName(): ?CarriedKeyName
72
    {
73
        return $this->carriedKeyName;
74
    }
75
76
77
    /**
78
     * Get the value of the Recipient attribute.
79
     *
80
     * @return \SimpleSAML\XMLSchema\Type\StringValue|null
81
     */
82
    public function getRecipient(): ?StringValue
83
    {
84
        return $this->recipient;
85
    }
86
87
88
    /**
89
     * Get the ReferenceList object.
90
     *
91
     * @return \SimpleSAML\XMLSecurity\XML\xenc\ReferenceList|null
92
     */
93
    public function getReferenceList(): ?ReferenceList
94
    {
95
        return $this->referenceList;
96
    }
97
98
99
    /**
100
     * @param \SimpleSAML\XMLSecurity\Alg\Encryption\EncryptionAlgorithmInterface $decryptor The decryptor to use
101
     * to decrypt the key.
102
     *
103
     * @return string The decrypted key.
104
     */
105
    public function decrypt(EncryptionAlgorithmInterface $decryptor): string
106
    {
107
        $cipherValue =  $this->getCipherData()->getCipherValue();
108
        Assert::notNull(
109
            $cipherValue,
110
            'Decrypting keys by reference is not supported.',
111
            InvalidArgumentException::class,
112
        );
113
114
        Assert::eq(
115
            $decryptor->getAlgorithmId(),
116
            $this->getEncryptionMethod()?->getAlgorithm(),
117
            'Decryptor algorithm does not match algorithm used.',
118
            InvalidArgumentException::class,
119
        );
120
121
        return $decryptor->decrypt(base64_decode($cipherValue->getContent()->getValue(), true));
122
    }
123
124
125
    /**
126
     * Create an EncryptedKey by encrypting a given key.
127
     *
128
     * @param \SimpleSAML\XMLSecurity\Key\KeyInterface $keyToEncrypt The key to encrypt.
129
     * @param \SimpleSAML\XMLSecurity\Alg\Encryption\EncryptionAlgorithmInterface $encryptor The encryptor to use.
130
     * @param \SimpleSAML\XMLSecurity\XML\xenc\EncryptionMethod $encryptionMethod
131
     *   The EncryptionMethod object of this EncryptedData. Optional.
132
     * @param \SimpleSAML\XMLSchema\Type\IDValue|null $id The Id attribute of this object. Optional.
133
     * @param \SimpleSAML\XMLSchema\Type\AnyURIValue|null $type The Type attribute of this object. Optional.
134
     * @param \SimpleSAML\XMLSchema\Type\StringValue|null $mimeType
135
     *   The MimeType attribute of this object. Optional.
136
     * @param \SimpleSAML\XMLSchema\Type\AnyURIValue|null $encoding
137
     *   The Encoding attribute of this object. Optional.
138
     * @param \SimpleSAML\XMLSchema\Type\StringValue|null $recipient
139
     *   The Recipient attribute of this object. Optional.
140
     * @param \SimpleSAML\XMLSecurity\XML\xenc\CarriedKeyName|null $carriedKeyName
141
     *   The value of the CarriedKeyName element of this EncryptedData.
142
     * @param \SimpleSAML\XMLSecurity\XML\ds\KeyInfo|null $keyInfo The KeyInfo object of this EncryptedData. Optional.
143
     * @param \SimpleSAML\XMLSecurity\XML\xenc\ReferenceList|null $referenceList
144
     *   The ReferenceList object of this EncryptedData. Optional.
145
     *
146
     * @return \SimpleSAML\XMLSecurity\XML\xenc\EncryptedKey The new EncryptedKey object.
147
     */
148
    public static function fromKey(
149
        KeyInterface $keyToEncrypt,
150
        EncryptionAlgorithmInterface $encryptor,
151
        EncryptionMethod $encryptionMethod,
152
        ?IDValue $id = null,
153
        ?AnyURIValue $type = null,
154
        ?StringValue $mimeType = null,
155
        ?AnyURIValue $encoding = null,
156
        ?StringValue $recipient = null,
157
        ?CarriedKeyName $carriedKeyName = null,
158
        ?KeyInfo $keyInfo = null,
159
        ?ReferenceList $referenceList = null,
160
    ): EncryptedKey {
161
        Assert::eq(
162
            $encryptor->getAlgorithmId(),
163
            $encryptionMethod->getAlgorithm()->getValue(),
164
            'Encryptor algorithm and encryption method do not match.',
165
            InvalidArgumentException::class,
166
        );
167
168
        return new self(
169
            new CipherData(
170
                new CipherValue(
171
                    Base64BinaryValue::fromString(base64_encode(
172
                        $encryptor->encrypt($keyToEncrypt->getMaterial()),
173
                    )),
174
                ),
175
            ),
176
            $id,
177
            $type,
178
            $mimeType,
179
            $encoding,
180
            $recipient,
181
            $carriedKeyName,
182
            $encryptionMethod,
183
            $keyInfo,
184
            $referenceList,
185
        );
186
    }
187
188
189
    /**
190
     * @inheritDoc
191
     *
192
     * @throws \SimpleSAML\XMLSchema\Exception\InvalidDOMElementException
193
     *   If the qualified name of the supplied element is wrong
194
     */
195
    public static function fromXML(DOMElement $xml): static
196
    {
197
        Assert::same($xml->localName, 'EncryptedKey', InvalidDOMElementException::class);
198
        Assert::same($xml->namespaceURI, EncryptedKey::NS, InvalidDOMElementException::class);
199
200
        $cipherData = CipherData::getChildrenOfClass($xml);
201
        Assert::count(
202
            $cipherData,
203
            1,
204
            'No or more than one CipherData element found in <xenc:EncryptedKey>.',
205
            TooManyElementsException::class,
206
        );
207
208
        $encryptionMethod = EncryptionMethod::getChildrenOfClass($xml);
209
        Assert::maxCount(
210
            $encryptionMethod,
211
            1,
212
            'No more than one EncryptionMethod element allowed in <xenc:EncryptedKey>.',
213
            TooManyElementsException::class,
214
        );
215
216
        $keyInfo = KeyInfo::getChildrenOfClass($xml);
217
        Assert::maxCount(
218
            $keyInfo,
219
            1,
220
            'No more than one KeyInfo element allowed in <xenc:EncryptedKey>.',
221
            TooManyElementsException::class,
222
        );
223
224
        $referenceLists = ReferenceList::getChildrenOfClass($xml);
225
        Assert::maxCount(
226
            $keyInfo,
227
            1,
228
            'Only one ReferenceList element allowed in <xenc:EncryptedKey>.',
229
            TooManyElementsException::class,
230
        );
231
232
        $carriedKeyNames = CarriedKeyName::getChildrenOfClass($xml);
233
        Assert::maxCount(
234
            $carriedKeyNames,
235
            1,
236
            'Only one CarriedKeyName element allowed in <xenc:EncryptedKey>.',
237
            TooManyElementsException::class,
238
        );
239
240
        return new static(
241
            $cipherData[0],
242
            self::getOptionalAttribute($xml, 'Id', IDValue::class, null),
243
            self::getOptionalAttribute($xml, 'Type', AnyURIValue::class, null),
244
            self::getOptionalAttribute($xml, 'MimeType', StringValue::class, null),
245
            self::getOptionalAttribute($xml, 'Encoding', AnyURIValue::class, null),
246
            self::getOptionalAttribute($xml, 'Recipient', StringValue::class, null),
247
            array_pop($carriedKeyNames),
248
            array_pop($encryptionMethod),
249
            array_pop($keyInfo),
250
            array_pop($referenceLists),
251
        );
252
    }
253
254
255
    /**
256
     * @inheritDoc
257
     */
258
    public function toXML(?DOMElement $parent = null): DOMElement
259
    {
260
        $e = parent::toXML($parent);
261
262
        if ($this->getRecipient() !== null) {
263
            $e->setAttribute('Recipient', strval($this->getRecipient()));
264
        }
265
266
        $this->getReferenceList()?->toXML($e);
267
        $this->getCarriedKeyName()?->toXML($e);
268
269
        return $e;
270
    }
271
}
272