Conditions | 18 |
Paths | 98 |
Total Lines | 147 |
Code Lines | 69 |
Lines | 0 |
Ratio | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
1 | <?php |
||
144 | private static function doDecryptElement( |
||
145 | DOMElement $encryptedData, |
||
146 | XMLSecurityKey $inputKey, |
||
147 | array &$blacklist |
||
148 | ): DOMElement { |
||
149 | $enc = new XMLSecEnc(); |
||
150 | |||
151 | $enc->setNode($encryptedData); |
||
152 | $enc->type = $encryptedData->getAttribute("Type"); |
||
153 | |||
154 | $symmetricKey = $enc->locateKey($encryptedData); |
||
155 | if (!$symmetricKey) { |
||
156 | throw new Exception('Could not locate key algorithm in encrypted data.'); |
||
157 | } |
||
158 | |||
159 | $symmetricKeyInfo = $enc->locateKeyInfo($symmetricKey); |
||
160 | if (!$symmetricKeyInfo) { |
||
161 | throw new Exception('Could not locate <dsig:KeyInfo> for the encrypted key.'); |
||
162 | } |
||
163 | |||
164 | $inputKeyAlgo = $inputKey->getAlgorithm(); |
||
165 | if ($symmetricKeyInfo->isEncrypted) { |
||
166 | $symKeyInfoAlgo = $symmetricKeyInfo->getAlgorithm(); |
||
167 | |||
168 | if (in_array($symKeyInfoAlgo, $blacklist, true)) { |
||
169 | throw new Exception('Algorithm disabled: ' . var_export($symKeyInfoAlgo, true)); |
||
170 | } |
||
171 | |||
172 | if ($symKeyInfoAlgo === XMLSecurityKey::RSA_OAEP_MGF1P && $inputKeyAlgo === XMLSecurityKey::RSA_1_5) { |
||
173 | /* |
||
174 | * The RSA key formats are equal, so loading an RSA_1_5 key |
||
175 | * into an RSA_OAEP_MGF1P key can be done without problems. |
||
176 | * We therefore pretend that the input key is an |
||
177 | * RSA_OAEP_MGF1P key. |
||
178 | */ |
||
179 | $inputKeyAlgo = XMLSecurityKey::RSA_OAEP_MGF1P; |
||
180 | } |
||
181 | |||
182 | /* Make sure that the input key format is the same as the one used to encrypt the key. */ |
||
183 | if ($inputKeyAlgo !== $symKeyInfoAlgo) { |
||
184 | throw new Exception( |
||
185 | 'Algorithm mismatch between input key and key used to encrypt ' . |
||
186 | ' the symmetric key for the message. Key was: ' . |
||
187 | var_export($inputKeyAlgo, true) . '; message was: ' . |
||
188 | var_export($symKeyInfoAlgo, true) |
||
189 | ); |
||
190 | } |
||
191 | |||
192 | /** @var XMLSecEnc $encKey */ |
||
193 | $encKey = $symmetricKeyInfo->encryptedCtx; |
||
194 | $symmetricKeyInfo->key = $inputKey->key; |
||
195 | |||
196 | $keySize = $symmetricKey->getSymmetricKeySize(); |
||
197 | if ($keySize === null) { |
||
198 | /* To protect against "key oracle" attacks, we need to be able to create a |
||
199 | * symmetric key, and for that we need to know the key size. |
||
200 | */ |
||
201 | throw new Exception( |
||
202 | 'Unknown key size for encryption algorithm: ' . var_export($symmetricKey->type, true) |
||
203 | ); |
||
204 | } |
||
205 | |||
206 | try { |
||
207 | /** |
||
208 | * @var string $key |
||
209 | * @psalm-suppress UndefinedClass |
||
210 | */ |
||
211 | $key = $encKey->decryptKey($symmetricKeyInfo); |
||
212 | if (strlen($key) !== $keySize) { |
||
213 | throw new Exception( |
||
214 | 'Unexpected key size (' . strval(strlen($key) * 8) . 'bits) for encryption algorithm: ' . |
||
215 | var_export($symmetricKey->type, true) |
||
216 | ); |
||
217 | } |
||
218 | } catch (Exception $e) { |
||
219 | /* We failed to decrypt this key. Log it, and substitute a "random" key. */ |
||
220 | // Utils::getContainer()->getLogger()->error('Failed to decrypt symmetric key: ' . $e->getMessage()); |
||
221 | /* Create a replacement key, so that it looks like we fail in the same way as if the key was correctly |
||
222 | * padded. */ |
||
223 | |||
224 | /* We base the symmetric key on the encrypted key and private key, so that we always behave the |
||
225 | * same way for a given input key. |
||
226 | */ |
||
227 | $encryptedKey = $encKey->getCipherValue(); |
||
228 | if ($encryptedKey === null) { |
||
229 | throw new Exception('No CipherValue available in the encrypted element.'); |
||
230 | } |
||
231 | |||
232 | /** @psalm-suppress PossiblyNullArgument */ |
||
233 | $pkey = openssl_pkey_get_details($symmetricKeyInfo->key); |
||
234 | $pkey = sha1(serialize($pkey), true); |
||
235 | $key = sha1($encryptedKey . $pkey, true); |
||
236 | |||
237 | /* Make sure that the key has the correct length. */ |
||
238 | if (strlen($key) > $keySize) { |
||
239 | $key = substr($key, 0, $keySize); |
||
240 | } elseif (strlen($key) < $keySize) { |
||
241 | $key = str_pad($key, $keySize); |
||
242 | } |
||
243 | } |
||
244 | $symmetricKey->loadkey($key); |
||
245 | } else { |
||
246 | $symKeyAlgo = $symmetricKey->getAlgorithm(); |
||
247 | /* Make sure that the input key has the correct format. */ |
||
248 | if ($inputKeyAlgo !== $symKeyAlgo) { |
||
249 | throw new Exception( |
||
250 | 'Algorithm mismatch between input key and key in message. ' . |
||
251 | 'Key was: ' . var_export($inputKeyAlgo, true) . '; message was: ' . |
||
252 | var_export($symKeyAlgo, true) |
||
253 | ); |
||
254 | } |
||
255 | $symmetricKey = $inputKey; |
||
256 | } |
||
257 | |||
258 | $algorithm = $symmetricKey->getAlgorithm(); |
||
259 | if (in_array($algorithm, $blacklist, true)) { |
||
260 | throw new Exception('Algorithm disabled: ' . var_export($algorithm, true)); |
||
261 | } |
||
262 | |||
263 | /** |
||
264 | * @var string $decrypted |
||
265 | * @psalm-suppress UndefinedClass |
||
266 | */ |
||
267 | $decrypted = $enc->decryptNode($symmetricKey, false); |
||
268 | |||
269 | /* |
||
270 | * This is a workaround for the case where only a subset of the XML |
||
271 | * tree was serialized for encryption. In that case, we may miss the |
||
272 | * namespaces needed to parse the XML. |
||
273 | */ |
||
274 | $xml = '<root xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ' . |
||
275 | 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' . |
||
276 | $decrypted . '</root>'; |
||
277 | |||
278 | try { |
||
279 | $newDoc = DOMDocumentFactory::fromString($xml); |
||
280 | } catch (RuntimeException $e) { |
||
281 | throw new Exception('Failed to parse decrypted XML. Maybe the wrong sharedkey was used?', 0, $e); |
||
282 | } |
||
283 | |||
284 | /** @psalm-suppress PossiblyNullPropertyFetch */ |
||
285 | $decryptedElement = $newDoc->firstChild->firstChild; |
||
286 | if (!($decryptedElement instanceof DOMElement)) { |
||
287 | throw new Exception('Missing decrypted element or it was not actually a DOMElement.'); |
||
288 | } |
||
289 | |||
290 | return $decryptedElement; |
||
291 | } |
||
320 |