Failed Conditions
Push — v7 ( 318c5f...2b71c7 )
by Florent
03:43
created

src/Loader.php (2 issues)

Labels
Severity

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
2
3
/*
4
 * The MIT License (MIT)
5
 *
6
 * Copyright (c) 2014-2016 Spomky-Labs
7
 *
8
 * This software may be modified and distributed under the terms
9
 * of the MIT license.  See the LICENSE file for details.
10
 */
11
12
namespace Jose;
13
14
use Jose\Object\JWEInterface;
15
use Jose\Object\JWKInterface;
16
use Jose\Object\JWKSet;
17
use Jose\Object\JWKSetInterface;
18
use Jose\Object\JWSInterface;
19
20
/**
21
 * Class able to load JWS or JWE.
22
 * JWS object can also be verified.
23
 */
24
final class Loader
25
{
26
    /**
27
     * @param $input
28
     * @param JWKInterface $jwk
29
     * @param array $allowed_key_encryption_algorithms
30
     * @param array $allowed_content_encryption_algorithms
31
     * @param int|null $recipient_index
32
     * @return JWEInterface
33
     */
34
    public function loadAndDecryptUsingKey($input, JWKInterface $jwk, array $allowed_key_encryption_algorithms, array $allowed_content_encryption_algorithms, ?int &$recipient_index = null): JWEInterface
35
    {
36
        $jwk_set = new JWKSet();
37
        $jwk_set->addKey($jwk);
38
39
        return $this->loadAndDecrypt($input, $jwk_set, $allowed_key_encryption_algorithms, $allowed_content_encryption_algorithms, $recipient_index);
40
    }
41
42
    /**
43
     * @param $input
44
     * @param JWKSetInterface $jwk_set
45
     * @param array $allowed_key_encryption_algorithms
46
     * @param array $allowed_content_encryption_algorithms
47
     * @param int|null $recipient_index
48
     * @return JWEInterface
49
     */
50
    public function loadAndDecryptUsingKeySet($input, JWKSetInterface $jwk_set, array $allowed_key_encryption_algorithms, array $allowed_content_encryption_algorithms, ?int &$recipient_index = null): JWEInterface
51
    {
52
        return $this->loadAndDecrypt($input, $jwk_set, $allowed_key_encryption_algorithms, $allowed_content_encryption_algorithms, $recipient_index);
53
    }
54
55
    /**
56
     * @param $input
57
     * @param JWKInterface $jwk
58
     * @param array $allowed_algorithms
59
     * @param int|null $signature_index
60
     * @return JWSInterface
61
     */
62
    public function loadAndVerifySignatureUsingKey($input, JWKInterface $jwk, array $allowed_algorithms, ?int &$signature_index = null): JWSInterface
63
    {
64
        $jwk_set = new JWKSet();
65
        $jwk_set->addKey($jwk);
66
67
        return $this->loadAndVerifySignature($input, $jwk_set, $allowed_algorithms, null, $signature_index);
68
    }
69
70
    /**
71
     * @param $input
72
     * @param JWKSetInterface $jwk_set
73
     * @param array $allowed_algorithms
74
     * @param int|null $signature_index
75
     * @return JWSInterface
76
     */
77
    public function loadAndVerifySignatureUsingKeySet($input, JWKSetInterface $jwk_set, array $allowed_algorithms, ?int &$signature_index = null): JWSInterface
78
    {
79
        return $this->loadAndVerifySignature($input, $jwk_set, $allowed_algorithms, null, $signature_index);
80
    }
81
82
    /**
83
     * @param $input
84
     * @param JWKInterface $jwk
85
     * @param array $allowed_algorithms
86
     * @param string $detached_payload
87
     * @param int|null $signature_index
88
     * @return JWSInterface
89
     */
90
    public function loadAndVerifySignatureUsingKeyAndDetachedPayload($input, JWKInterface $jwk, array $allowed_algorithms, string $detached_payload, ?int &$signature_index = null): JWSInterface
91
    {
92
        $jwk_set = new JWKSet();
93
        $jwk_set->addKey($jwk);
94
95
        return $this->loadAndVerifySignature($input, $jwk_set, $allowed_algorithms, $detached_payload, $signature_index);
96
    }
97
98
    /**
99
     * @param $input
100
     * @param JWKSetInterface $jwk_set
101
     * @param array $allowed_algorithms
102
     * @param string $detached_payload
103
     * @param int|null $signature_index
104
     * @return JWSInterface
105
     */
106
    public function loadAndVerifySignatureUsingKeySetAndDetachedPayload($input, JWKSetInterface $jwk_set, array $allowed_algorithms, string $detached_payload, ?int &$signature_index = null): JWSInterface
107
    {
108
        return $this->loadAndVerifySignature($input, $jwk_set, $allowed_algorithms, $detached_payload, $signature_index);
109
    }
110
111
    /**
112
     * @param string                       $input
113
     * @param JWKSetInterface $jwk_set
114
     * @param array                        $allowed_key_encryption_algorithms
115
     * @param array                        $allowed_content_encryption_algorithms
116
     * @param null|int                     $recipient_index
117
     *
118
     * @return JWEInterface
119
     */
120
    private function loadAndDecrypt(string $input, JWKSetInterface $jwk_set, array $allowed_key_encryption_algorithms, array $allowed_content_encryption_algorithms, ?int &$recipient_index = null): JWEInterface
121
    {
122
        $jwt = $this->load($input);
123
        if (!$jwt instanceof JWEInterface) {
124
            throw new \InvalidArgumentException('The input is not a valid JWE.');
125
        }
126
        $decrypted = Decrypter::createDecrypter($allowed_key_encryption_algorithms, $allowed_content_encryption_algorithms, ['DEF', 'ZLIB', 'GZ']);
127
128
        $decrypted->decryptUsingKeySet($jwt, $jwk_set, $recipient_index);
129
130
        return $jwt;
131
    }
132
133
    /**
134
     * @param string                       $input
135
     * @param JWKSetInterface $jwk_set
136
     * @param array                        $allowed_algorithms
137
     * @param string|null                  $detached_payload
138
     * @param null|int                     $signature_index
139
     *
140
     * @return JWSInterface
141
     */
142
    private function loadAndVerifySignature(string $input, JWKSetInterface $jwk_set, array $allowed_algorithms, string $detached_payload = null, ?int &$signature_index = null): JWSInterface
143
    {
144
        $jwt = $this->load($input);
145
        if (!$jwt instanceof JWSInterface) {
146
            throw new \InvalidArgumentException('The input is not a valid JWS.');
147
        }
148
        $verifier = Verifier::createVerifier($allowed_algorithms);
149
150
        $verifier->verifyWithKeySet($jwt, $jwk_set, $detached_payload, $signature_index);
0 ignored issues
show
It seems like $detached_payload defined by parameter $detached_payload on line 142 can also be of type string; however, Jose\Verifier::verifyWithKeySet() does only seem to accept null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
It seems like $signature_index defined by parameter $signature_index on line 142 can also be of type integer; however, Jose\Verifier::verifyWithKeySet() does only seem to accept null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
151
152
        return $jwt;
153
    }
154
155
    /**
156
     * @param string $input
157
     * @return JWEInterface|JWSInterface
158
     */
159
    public function load(string $input)
160
    {
161
        $json = $this->convert($input);
162
        if (array_key_exists('signatures', $json)) {
163
            return Util\JWSLoader::loadSerializedJsonJWS($json);
164
        }
165
        if (array_key_exists('recipients', $json)) {
166
            return Util\JWELoader::loadSerializedJsonJWE($json);
167
        }
168
    }
169
170
    /**
171
     * @param string $input
172
     *
173
     * @return array
174
     */
175
    private function convert(string $input): array
176
    {
177
        if (is_array($data = json_decode($input, true))) {
178
            if (array_key_exists('signatures', $data) || array_key_exists('recipients', $data)) {
179
                return $data;
180
            } elseif (array_key_exists('signature', $data)) {
181
                return $this->fromFlattenedSerializationSignatureToSerialization($data);
182
            } elseif (array_key_exists('ciphertext', $data)) {
183
                return $this->fromFlattenedSerializationRecipientToSerialization($data);
184
            }
185
        } elseif (is_string($input)) {
186
            return $this->fromCompactSerializationToSerialization($input);
187
        }
188
        throw new \InvalidArgumentException('Unsupported input');
189
    }
190
191
    /**
192
     * @param array $input
193
     * @return array
194
     */
195
    private function fromFlattenedSerializationRecipientToSerialization(array $input): array
196
    {
197
        $recipient = [];
198
        foreach (['header', 'encrypted_key'] as $key) {
199
            if (array_key_exists($key, $input)) {
200
                $recipient[$key] = $input[$key];
201
            }
202
        }
203
        $recipients = [
204
            'ciphertext' => $input['ciphertext'],
205
            'recipients' => [$recipient],
206
        ];
207
        foreach (['protected', 'unprotected', 'iv', 'aad', 'tag'] as $key) {
208
            if (array_key_exists($key, $input)) {
209
                $recipients[$key] = $input[$key];
210
            }
211
        }
212
213
        return $recipients;
214
    }
215
216
    /**
217
     * @param array $input
218
     * @return array
219
     */
220
    private function fromFlattenedSerializationSignatureToSerialization(array $input): array
221
    {
222
        $signature = [
223
            'signature' => $input['signature'],
224
        ];
225
        foreach (['protected', 'header'] as $key) {
226
            if (array_key_exists($key, $input)) {
227
                $signature[$key] = $input[$key];
228
            }
229
        }
230
231
        $temp = [];
232
        if (!empty($input['payload'])) {
233
            $temp['payload'] = $input['payload'];
234
        }
235
        $temp['signatures'] = [$signature];
236
237
        return $temp;
238
    }
239
240
    /**
241
     * @param string $input
242
     *
243
     * @return array
244
     */
245
    private function fromCompactSerializationToSerialization($input)
246
    {
247
        $parts = explode('.', $input);
248
        switch (count($parts)) {
249
            case 3:
250
                return $this->fromCompactSerializationSignatureToSerialization($parts);
251
            case 5:
252
                return $this->fromCompactSerializationRecipientToSerialization($parts);
253
            default:
254
                throw new \InvalidArgumentException('Unsupported input');
255
        }
256
    }
257
258
    /**
259
     * @param array $parts
260
     *
261
     * @return array
262
     */
263
    private function fromCompactSerializationRecipientToSerialization(array $parts): array
264
    {
265
        $recipient = [];
266
        if (!empty($parts[1])) {
267
            $recipient['encrypted_key'] = $parts[1];
268
        }
269
270
        $recipients = [
271
            'recipients' => [$recipient],
272
        ];
273
        foreach ([0 => 'protected', 2 => 'iv', 3 => 'ciphertext', 4 => 'tag'] as $part => $key) {
274
            if (!empty($parts[$part])) {
275
                $recipients[$key] = $parts[$part];
276
            }
277
        }
278
279
        return $recipients;
280
    }
281
282
    /**
283
     * @param array $parts
284
     *
285
     * @return array
286
     */
287
    private function fromCompactSerializationSignatureToSerialization(array $parts): array
288
    {
289
        $temp = [];
290
291
        if (!empty($parts[1])) {
292
            $temp['payload'] = $parts[1];
293
        }
294
        $temp['signatures'] = [[
295
            'protected' => $parts[0],
296
            'signature' => $parts[2],
297
        ]];
298
299
        return $temp;
300
    }
301
}
302