Issues (50)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/jwe/impl/JWE.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php namespace jwe\impl;
2
/**
3
 * Copyright 2015 OpenStack Foundation
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 * http://www.apache.org/licenses/LICENSE-2.0
8
 * Unless required by applicable law or agreed to in writing, software
9
 * distributed under the License is distributed on an "AS IS" BASIS,
10
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
 * See the License for the specific language governing permissions and
12
 * limitations under the License.
13
 **/
14
use jwa\cryptographic_algorithms\ContentEncryptionAlgorithms_Registry;
15
use jwa\cryptographic_algorithms\EncryptionAlgorithm;
16
use jwa\cryptographic_algorithms\exceptions\InvalidKeyTypeAlgorithmException;
17
use jwa\cryptographic_algorithms\key_management\modes\DirectEncryption;
18
use jwa\cryptographic_algorithms\key_management\modes\DirectKeyAgreement;
19
use jwa\cryptographic_algorithms\key_management\modes\KeyAgreementWithKeyWrapping;
20
use jwa\cryptographic_algorithms\key_management\modes\KeyEncryption;
21
use jwa\cryptographic_algorithms\key_management\modes\KeyWrapping;
22
use jwa\cryptographic_algorithms\KeyManagementAlgorithms_Registry;
23
use jwe\exceptions\JWEInvalidCompactFormatException;
24
use jwe\exceptions\JWEInvalidRecipientKeyException;
25
use jwe\exceptions\JWEUnsupportedContentEncryptionAlgorithmException;
26
use jwe\exceptions\JWEUnsupportedKeyManagementAlgorithmException;
27
use jwe\compression_algorithms\CompressionAlgorithms_Registry;
28
use jwe\IJWEJOSEHeader;
29
use jwe\IJWE;
30
use jwe\KeyManagementModeValues;
31
use jwk\exceptions\InvalidJWKAlgorithm;
32
use jwk\IJWK;
33
use jwk\JSONWebKeyKeyOperationsValues;
34
use jws\IJWSPayloadRawSpec;
35
use jws\IJWSPayloadSpec;
36
use jws\payloads\JWSPayloadFactory;
37
use jwt\utils\JOSEHeaderSerializer;
38
use security\Key;
39
/**
40
 * Class JWE
41
 * @package jwe\impl
42
 * @access private
43
 */
44
final class JWE implements IJWE, IJWESnapshot
45
{
46
47
    /**
48
     * @var IJWK
49
     */
50
    private $jwk = null;
51
52
    /**
53
     * @var IJWSPayloadSpec
54
     */
55
    private $payload = null;
56
57
    /**
58
     * @var IJWEJOSEHeader
59
     */
60
    private $header;
61
62
    /**
63
     * @var Key
64
     */
65
    private $cek = null;
66
67
    /**
68
     * @var string
69
     */
70
    private $tag = null;
71
72
    /**
73
     * @var string
74
     */
75
    private $cipher_text = null;
76
77
    /**
78
     * @var string
79
     */
80
    private $iv;
81
82
    /**
83
     * @var string
84
     */
85
    private $enc_cek = null;
86
87
    private $should_decrypt = false;
88
89
    /**
90
     * @param IJWEJOSEHeader $header
91
     * @param IJWSPayloadSpec $payload
92
     */
93
    protected function __construct(IJWEJOSEHeader $header, IJWSPayloadSpec $payload = null)
94
    {
95
        $this->header = $header;
96
        if(!is_null($payload))
97
            $this->setPayload($payload);
98
    }
99
100
    /**
101
     * @param IJWK $recipient_key
102
     * @return $this
103
     */
104
    public function setRecipientKey(IJWK $recipient_key)
105
    {
106
        $this->jwk = $recipient_key;
107
        return $this;
108
    }
109
110
    /**
111
     * @param IJWSPayloadSpec $payload
112
     * @return $this
113
     */
114
    public function setPayload(IJWSPayloadSpec $payload)
115
    {
116
        $this->payload = $payload;
117
        return $this;
118
    }
119
120
    /**
121
     * @param int $size
122
     * @return String
123
     */
124
    protected function createIV($size)
125
    {
126
        return IVFactory::build($size);
127
    }
128
129
    /**
130
     * @throws JWEInvalidRecipientKeyException
131
     * @throws JWEUnsupportedContentEncryptionAlgorithmException
132
     * @throws JWEUnsupportedKeyManagementAlgorithmException
133
     * @return string
134
     */
135
    public function toCompactSerialization()
136
    {
137
        return JWESerializer::serialize($this->encrypt());
138
    }
139
140
    /**
141
     * @return mixed
142
     * @throws JWEInvalidRecipientKeyException
143
     * @throws JWEUnsupportedContentEncryptionAlgorithmException
144
     * @throws JWEUnsupportedKeyManagementAlgorithmException
145
     */
146
    public function getPlainText()
147
    {
148
        if ($this->should_decrypt)
149
        {
150
            $this->decrypt();
151
        }
152
153
        if (is_null($this->payload))
154
            $this->payload = JWSPayloadFactory::build('');
155
156
        return ($this->payload instanceof IJWSPayloadRawSpec) ? $this->payload->getRaw():'';
157
    }
158
159
    /**
160
     * @return IJWEJOSEHeader
161
     */
162
    public function getJOSEHeader()
163
    {
164
        return $this->header;
165
    }
166
167
168
    /***
169
     * @param EncryptionAlgorithm $alg
170
     * @param Key $recipient_public_key
171
     * @return string
172
     */
173
     private function getJWEEncryptedKey(EncryptionAlgorithm $alg, Key $recipient_public_key)
174
     {
175
        /**
176
         * When Key Wrapping, Key Encryption, or Key Agreement with Key
177
         * Wrapping are employed, encrypt the CEK to the recipient and let
178
         * the result be the JWE Encrypted Key.
179
         */
180
         $key_management_mode = $this->getKeyManagementMode($alg);
181
         switch($key_management_mode){
182
             case KeyManagementModeValues::KeyEncryption:
183
             case KeyManagementModeValues::KeyWrapping:
184
             case KeyManagementModeValues::KeyAgreementWithKeyWrapping:
185
             {
186
                 return $alg->encrypt($recipient_public_key, $this->cek->getEncoded());
187
             }
188
             /**
189
              * When Direct Key Agreement or Direct Encryption are employed, let
190
              * the JWE Encrypted Key be the empty octet sequence.
191
              */
192
             default:
193
             return '';
194
         }
195
     }
196
197
    /**
198
     * Determine the Key Management Mode employed by the algorithm used
199
     * to determine the Content Encryption Key value.  (This is the
200
     * algorithm recorded in the "alg" (algorithm) Header Parameter of
201
     * the resulting JWE.)
202
     * @param EncryptionAlgorithm $alg
203
     * @return string
204
     */
205
    private function getKeyManagementMode(EncryptionAlgorithm $alg)
206
    {
207
        if($alg instanceof KeyEncryption)
208
            return KeyManagementModeValues::KeyEncryption;
209
        if($alg instanceof KeyWrapping)
210
            return KeyManagementModeValues::KeyWrapping;
211
        if($alg instanceof DirectKeyAgreement)
212
            return KeyManagementModeValues::DirectKeyAgreement;
213
        if($alg instanceof KeyAgreementWithKeyWrapping)
214
            return KeyManagementModeValues::KeyAgreementWithKeyWrapping;
215
        if($alg instanceof DirectEncryption)
216
            return KeyManagementModeValues::DirectEncryption;
217
    }
218
219
    /**
220
     * @return $this
221
     * @throws InvalidJWKAlgorithm
222
     * @throws InvalidKeyTypeAlgorithmException
223
     * @throws JWEInvalidRecipientKeyException
224
     * @throws JWEUnsupportedContentEncryptionAlgorithmException
225
     * @throws JWEUnsupportedKeyManagementAlgorithmException
226
     * @throws \Exception
227
     */
228
    private function encrypt()
229
    {
230
231
        if (is_null($this->jwk))
232
            throw new JWEInvalidRecipientKeyException;
233
234 View Code Duplication
        if($this->jwk->getAlgorithm()->getValue()!== $this->header->getAlgorithm()->getString())
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
235
            throw new InvalidJWKAlgorithm
236
            (
237
                sprintf
238
                (
239
                    'mismatch between algorithm intended for use with the key %s and the cryptographic algorithm used to encrypt or determine the value of the CEK %s',
240
                    $this->jwk->getAlgorithm()->getValue(),
241
                    $this->header->getAlgorithm()->getString()
242
                )
243
            );
244
245
        $recipient_public_key     = $this->jwk->getKey(JSONWebKeyKeyOperationsValues::EncryptContent);
246
247
        $key_management_algorithm = KeyManagementAlgorithms_Registry::getInstance()->get($this->header->getAlgorithm()->getString());
248
249
        if (is_null($key_management_algorithm))
250
            throw new JWEUnsupportedKeyManagementAlgorithmException(sprintf('alg %s', $this->header->getAlgorithm()->getString()));
251
252
        if($key_management_algorithm->getKeyType() !== $recipient_public_key->getAlgorithm())
253
            throw new InvalidKeyTypeAlgorithmException
254
            (
255
                sprintf
256
                (
257
                    'key should be for alg %s, %s instead.',
258
                    $key_management_algorithm->getKeyType(),
259
                    $recipient_public_key->getAlgorithm()
260
                )
261
            );
262
263
        $content_encryption_algorithm = ContentEncryptionAlgorithms_Registry::getInstance()->get
264
        (
265
            $this->header->getEncryptionAlgorithm()->getString()
266
        );
267
268
        if (is_null($content_encryption_algorithm))
269
            throw new JWEUnsupportedContentEncryptionAlgorithmException
270
            (
271
                sprintf
272
                (
273
                    'enc %s',
274
                    $this->header->getEncryptionAlgorithm()->getString()
275
                )
276
            );
277
278
        $key_management_mode = $this->getKeyManagementMode($key_management_algorithm);
279
280
        $this->cek     = ContentEncryptionKeyFactory::build
281
        (
282
            $recipient_public_key,
283
            $key_management_mode,
284
            $content_encryption_algorithm
285
        );
286
287
        $this->enc_cek = $this->getJWEEncryptedKey($key_management_algorithm, $recipient_public_key);
288
289
        /**
290
         * Generate a random JWE Initialization Vector of the correct size
291
         * for the content encryption algorithm (if required for the
292
         * algorithm); otherwise, let the JWE Initialization Vector be the
293
         * empty octet sequence.
294
         */
295
        $this->iv      = '';
296
297
        if (!is_null($iv_size = $content_encryption_algorithm->getIVSize()))
298
        {
299
            $this->iv = $this->createIV($iv_size);
300
        }
301
        // We encrypt the payload and get the tag
302
        $jwt_shared_protected_header = JOSEHeaderSerializer::serialize($this->header);
303
304
        $payload = ($this->payload instanceof IJWSPayloadRawSpec) ? $this->payload->getRaw():'';
305
        $zip     = $this->header->getCompressionAlgorithm();
306
        /**
307
         * If a "zip" parameter was included, compress the plaintext using
308
         * the specified compression algorithm and let M be the octet
309
         * sequence representing the compressed plaintext; otherwise, let M
310
         * be the octet sequence representing the plaintext.
311
         */
312 View Code Duplication
        if(!is_null($zip))
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
313
        {
314
            $compression__algorithm = CompressionAlgorithms_Registry::getInstance()->get($zip->getValue());
315
            $payload  = $compression__algorithm->compress($payload);
316
        }
317
318
        /**
319
         * Encrypt M using the CEK, the JWE Initialization Vector, and the
320
         * Additional Authenticated Data value using the specified content
321
         * encryption algorithm to create the JWE Ciphertext value and the
322
         * JWE Authentication Tag (which is the Authentication Tag output
323
         * from the encryption operation).
324
         */
325
        list($this->cipher_text, $this->tag) = $content_encryption_algorithm->encrypt
326
        (
327
            $payload,
328
            $this->cek->getEncoded(),
329
            $this->iv,
330
            $jwt_shared_protected_header
331
        );
332
333
        return $this;
334
    }
335
336
337
    /**
338
     * @param EncryptionAlgorithm $alg
339
     * @return null|Key
340
     * @throws JWEInvalidCompactFormatException
341
     * @throws InvalidKeyTypeAlgorithmException
342
     * @throws \Exception
343
     */
344
    private function decryptJWEEncryptedKey(EncryptionAlgorithm $alg){
345
346
        $key_management_mode   = $this->getKeyManagementMode($alg);
347
        $recipient_private_key = $this->jwk->getKey(JSONWebKeyKeyOperationsValues::DecryptContentAndValidateDecryption);
348
349
        if($alg->getKeyType() !== $recipient_private_key->getAlgorithm())
350
            throw new InvalidKeyTypeAlgorithmException
351
            (
352
                sprintf
353
                (
354
                    'key should be for alg %s, %s instead.',
355
                    $alg->getKeyType(),
356
                    $recipient_private_key->getAlgorithm()
357
                )
358
            );
359
360
        switch($key_management_mode){
361
            /**
362
             * When Key Wrapping, Key Encryption, or Key Agreement with Key
363
             * Wrapping are employed, decrypt the JWE Encrypted Key to produce
364
             * the CEK.  The CEK MUST have a length equal to that required for
365
             * the content encryption algorithm
366
             */
367
            case KeyManagementModeValues::KeyEncryption:
368
            case KeyManagementModeValues::KeyWrapping:
369
            case KeyManagementModeValues::KeyAgreementWithKeyWrapping:
370
            {
371
372
                return ContentEncryptionKeyFactory::fromRaw($alg->decrypt($recipient_private_key, $this->enc_cek), $alg);
373
            }
374
            /**
375
             * When Direct Key Agreement or Direct Encryption are employed,
376
             * verify that the JWE Encrypted Key value is an empty octetsequence.
377
             * When Direct Encryption is employed, let the CEK be the shared
378
             * symmetric key.
379
             */
380
            case KeyManagementModeValues::DirectEncryption:
381
            {
382
                if (!empty($this->enc_cek))
383
                    throw new JWEInvalidCompactFormatException('JWE Encrypted Key value is not an empty octetsequence.');
384
                return $recipient_private_key;
385
            }
386
            case KeyManagementModeValues::DirectKeyAgreement:
387
            {
388
                if (!empty($this->enc_cek))
389
                    throw new JWEInvalidCompactFormatException('JWE Encrypted Key value is not an empty octetsequence.');
390
                throw new \Exception('unsupported Key Management Mode!');
391
            }
392
        }
393
        return null;
394
    }
395
396
    /**
397
     * @return $this
398
     * @throws InvalidJWKAlgorithm
399
     * @throws InvalidKeyTypeAlgorithmException
400
     * @throws JWEInvalidCompactFormatException
401
     * @throws JWEInvalidRecipientKeyException
402
     * @throws JWEUnsupportedContentEncryptionAlgorithmException
403
     * @throws JWEUnsupportedKeyManagementAlgorithmException
404
     * @throws \Exception
405
     */
406
    private function decrypt()
407
    {
408
        if (is_null($this->jwk))
409
            throw new JWEInvalidRecipientKeyException();
410
411
        if (!$this->should_decrypt) return $this;
412
413 View Code Duplication
        if($this->jwk->getAlgorithm()->getValue()!== $this->header->getAlgorithm()->getString())
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
414
            throw new InvalidJWKAlgorithm
415
            (
416
                sprintf
417
                (
418
                    'mismatch between algorithm intended for use with the key %s and the cryptographic algorithm used to encrypt or determine the value of the CEK %s',
419
                    $this->jwk->getAlgorithm()->getValue(),
420
                    $this->header->getAlgorithm()->getString()
421
                )
422
            );
423
424
        $key_management_algorithm = KeyManagementAlgorithms_Registry::getInstance()->get
425
        (
426
            $this->header->getAlgorithm()->getString()
427
        );
428
429
        if (is_null($key_management_algorithm))
430
            throw new JWEUnsupportedKeyManagementAlgorithmException
431
            (
432
                sprintf
433
                (
434
                    'alg %s',
435
                    $this->header->getAlgorithm()->getString()
436
                )
437
            );
438
439
        $content_encryption_algorithm = ContentEncryptionAlgorithms_Registry::getInstance()->get
440
        (
441
            $this->header->getEncryptionAlgorithm()->getString()
442
        );
443
444
        if (is_null($content_encryption_algorithm))
445
            throw new JWEUnsupportedContentEncryptionAlgorithmException
446
            (
447
                sprintf
448
                (
449
                    'enc %s',
450
                    $this->header->getEncryptionAlgorithm()->getString()
451
                )
452
            );
453
454
        $this->cek = $this->decryptJWEEncryptedKey($key_management_algorithm);
455
456
        // We encrypt the payload and get the tag
457
        $jwt_shared_protected_header = JOSEHeaderSerializer::serialize($this->header);
458
459
        /**
460
         * Decrypt the JWE Cipher Text using the CEK, the JWE Initialization
461
         * Vector, the Additional Authenticated Data value, and the JWE
462
         * Authentication Tag (which is the Authentication Tag input to the
463
         * calculation) using the specified content encryption algorithm,
464
         * returning the decrypted plaintext and validating the JWE
465
         * Authentication Tag in the manner specified for the algorithm,
466
         * rejecting the input without emitting any decrypted output if the
467
         * JWE Authentication Tag is incorrect.
468
         */
469
        $plain_text = $content_encryption_algorithm->decrypt
470
        (
471
            $this->cipher_text,
472
            $this->cek->getEncoded(),
473
            $this->iv,
474
            $jwt_shared_protected_header,
475
            $this->tag
476
        );
477
478
        $zip     = $this->header->getCompressionAlgorithm();
479
        /**
480
         * If a "zip" parameter was included, uncompress the decrypted
481
         * plaintext using the specified compression algorithm.
482
         */
483 View Code Duplication
        if(!is_null($zip))
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
484
        {
485
            $compression__algorithm = CompressionAlgorithms_Registry::getInstance()->get($zip->getValue());
486
            $plain_text = $compression__algorithm->uncompress($plain_text);
487
        }
488
489
        $this->setPayload(JWSPayloadFactory::build($plain_text));
490
        $this->should_decrypt = false;
491
492
        return $this;
493
    }
494
495
    /**
496
     * @return array
497
     */
498
    public function take()
499
    {
500
        return array(
501
            $this->header,
502
            $this->enc_cek,
503
            $this->iv,
504
            $this->cipher_text,
505
            $this->tag);
506
    }
507
508
    /**
509
     * @param IJWEJOSEHeader $header
510
     * @param IJWSPayloadSpec $payload
511
     * @return IJWE
512
     */
513
    public static function fromHeaderAndPayload(IJWEJOSEHeader $header, IJWSPayloadSpec $payload)
514
    {
515
        return new JWE($header, $payload);
516
    }
517
518
    /**
519
     * @param string $compact_serialization
520
     * @return IJWE
521
     * @throws JWEInvalidCompactFormatException
522
     * @access private
523
     */
524
    public static function fromCompactSerialization($compact_serialization)
525
    {
526
        list($header, $enc_cek, $iv, $cipher_text, $tag) = JWESerializer::deserialize($compact_serialization);
527
        $jwe = new JWE($header);
528
        $jwe->iv = $iv;
529
        $jwe->tag = $tag;
530
        $jwe->enc_cek = $enc_cek;
531
        $jwe->cipher_text = $cipher_text;
532
        $jwe->should_decrypt = true;
533
        return $jwe;
534
    }
535
}