These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
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 | |||
15 | namespace jws\impl; |
||
16 | |||
17 | use jwa\cryptographic_algorithms\digital_signatures\DigitalSignatureAlgorithm; |
||
18 | use jwa\cryptographic_algorithms\DigitalSignatures_MACs_Registry; |
||
19 | use jwa\cryptographic_algorithms\macs\MAC_Algorithm; |
||
20 | use jwk\exceptions\InvalidJWKAlgorithm; |
||
21 | use jwk\IAsymmetricJWK; |
||
22 | use jwk\IJWK; |
||
23 | use jwk\JSONWebKeyKeyOperationsValues; |
||
24 | use jwk\JSONWebKeyPublicKeyUseValues; |
||
25 | use jwk\JSONWebKeyVisibility; |
||
26 | use jws\exceptions\JWSInvalidJWKException; |
||
27 | use jws\exceptions\JWSInvalidPayloadException; |
||
28 | use jws\exceptions\JWSNotSupportedAlgorithm; |
||
29 | use jws\IJWS; |
||
30 | use jws\IJWSPayloadClaimSetSpec; |
||
31 | use jws\IJWSPayloadSpec; |
||
32 | use jws\payloads\JWSPayloadFactory; |
||
33 | use jwt\IBasicJWT; |
||
34 | use jwt\IJOSEHeader; |
||
35 | use jwt\impl\JWT; |
||
36 | use jwt\impl\JWTSerializer; |
||
37 | use jwt\JOSEHeaderParam; |
||
38 | use jwt\RegisteredJOSEHeaderNames; |
||
39 | use jwt\utils\JOSEHeaderSerializer; |
||
40 | use jwt\utils\JWTClaimSetSerializer; |
||
41 | use jwt\utils\JWTRawSerializer; |
||
42 | use utils\json_types\JsonArray; |
||
43 | use utils\json_types\JsonValue; |
||
44 | use utils\json_types\StringOrURI; |
||
45 | |||
46 | /** |
||
47 | * Class JWS |
||
48 | * @package jws\impl |
||
49 | * @access private |
||
50 | */ |
||
51 | final class JWS extends JWT implements IJWS |
||
52 | { |
||
53 | |||
54 | /** |
||
55 | * @var IJWK |
||
56 | */ |
||
57 | private $jwk = null; |
||
58 | |||
59 | /** |
||
60 | * @var IJWSPayloadSpec |
||
61 | */ |
||
62 | private $payload = null; |
||
63 | |||
64 | /** |
||
65 | * @param IJOSEHeader $header |
||
66 | * @param IJWSPayloadSpec $payload |
||
67 | * @param string $signature |
||
68 | * @throws JWSNotSupportedAlgorithm |
||
69 | */ |
||
70 | protected function __construct(IJOSEHeader $header, IJWSPayloadSpec $payload = null, $signature = '') |
||
71 | { |
||
72 | |||
73 | $claim_set = null; |
||
74 | |||
75 | if(!is_null($payload) && $payload->isClaimSet() && $payload instanceof IJWSPayloadClaimSetSpec) { |
||
76 | $header->addHeader(new JOSEHeaderParam(RegisteredJOSEHeaderNames::Type, new StringOrURI('JWT'))); |
||
77 | $claim_set = $payload->getClaimSet(); |
||
78 | } |
||
79 | |||
80 | parent::__construct($header, $claim_set); |
||
81 | |||
82 | if(!is_null($payload)) |
||
83 | $this->setPayload($payload); |
||
84 | |||
85 | $this->signature = $signature; |
||
86 | } |
||
87 | |||
88 | /** |
||
89 | * @param IJWSPayloadSpec $payload |
||
90 | * @return IJWS |
||
91 | */ |
||
92 | public function setPayload(IJWSPayloadSpec $payload) |
||
93 | { |
||
94 | $this->payload = $payload; |
||
95 | return $this; |
||
96 | } |
||
97 | |||
98 | /** |
||
99 | * @return string |
||
100 | */ |
||
101 | public function toCompactSerialization() |
||
102 | { |
||
103 | if(!is_null($this->jwk->getId())) |
||
104 | $this->header->addHeader(new JOSEHeaderParam(RegisteredJOSEHeaderNames::KeyID, $this->jwk->getId())); |
||
105 | |||
106 | if($this->jwk instanceof IAsymmetricJWK) |
||
107 | { |
||
108 | // we should add the public key on the header |
||
109 | $public_key = clone $this->jwk; |
||
110 | |||
111 | $this->header->addHeader |
||
112 | ( |
||
113 | new JOSEHeaderParam |
||
114 | ( |
||
115 | RegisteredJOSEHeaderNames::JSONWebKey, |
||
116 | new JsonValue |
||
117 | ( |
||
118 | $public_key->setVisibility(JSONWebKeyVisibility::PublicOnly) |
||
119 | ) |
||
120 | ) |
||
121 | ); |
||
122 | } |
||
123 | |||
124 | $this->sign(); |
||
125 | return parent::toCompactSerialization(); |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * @return $this |
||
130 | * @throws JWSInvalidJWKException |
||
131 | * @throws JWSInvalidPayloadException |
||
132 | * @throws JWSNotSupportedAlgorithm |
||
133 | */ |
||
134 | public function sign() |
||
135 | { |
||
136 | |||
137 | if(is_null($this->jwk)) |
||
138 | throw new JWSInvalidJWKException; |
||
139 | |||
140 | View Code Duplication | if($this->jwk->getKeyUse()->getString() !== JSONWebKeyPublicKeyUseValues::Signature) |
|
141 | throw new JWSInvalidJWKException(sprintf('use %s not supported.', $this->jwk->getKeyUse()->getString())); |
||
142 | |||
143 | $alg = DigitalSignatures_MACs_Registry::getInstance()->get($this->header->getAlgorithm()->getString()); |
||
144 | |||
145 | if(is_null($alg)) |
||
146 | throw new JWSNotSupportedAlgorithm(sprintf('alg %s.',$this->header->getAlgorithm()->getString())); |
||
147 | |||
148 | $secured_input_bytes = JOSEHeaderSerializer::serialize($this->header) . IBasicJWT::SegmentSeparator .$this->getEncodedPayload(); |
||
149 | |||
150 | $key = $this->jwk->getKey(JSONWebKeyKeyOperationsValues::ComputeDigitalSignatureOrMAC); |
||
151 | |||
152 | if($alg instanceof DigitalSignatureAlgorithm) |
||
153 | { |
||
154 | $this->signature = $alg->sign($key, $secured_input_bytes); |
||
155 | } |
||
156 | else if($alg instanceof MAC_Algorithm ) |
||
157 | { |
||
158 | $this->signature = $alg->digest($key, $secured_input_bytes); |
||
159 | } |
||
160 | else |
||
161 | { |
||
162 | throw new JWSNotSupportedAlgorithm(sprintf('alg %s.',$this->header->getAlgorithm()->getString())); |
||
163 | } |
||
164 | |||
165 | return $this; |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * @return string |
||
170 | * @throws JWSInvalidPayloadException |
||
171 | */ |
||
172 | public function getEncodedPayload() |
||
173 | { |
||
174 | if(is_null($this->payload)) |
||
175 | throw new JWSInvalidPayloadException('payload is not set!'); |
||
176 | |||
177 | $enc_payload = ''; |
||
0 ignored issues
–
show
|
|||
178 | if($this->payload->isClaimSet() && $this->payload instanceof IJWSPayloadClaimSetSpec) |
||
179 | { |
||
180 | $enc_payload = JWTClaimSetSerializer::serialize($this->payload->getClaimSet()); |
||
181 | } |
||
182 | else |
||
183 | { |
||
184 | $enc_payload = JWTRawSerializer::serialize($this->payload->getRaw()); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
jws\IJWSPayloadSpec as the method getRaw() does only exist in the following implementations of said interface: jws\payloads\_JWSPayloadRawSpec .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
Loading history...
|
|||
185 | } |
||
186 | return $enc_payload; |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * @param IJWK $key |
||
191 | * @return $this |
||
192 | */ |
||
193 | public function setKey(IJWK $key) |
||
194 | { |
||
195 | $this->jwk = $key; |
||
196 | return $this; |
||
197 | } |
||
198 | |||
199 | /** |
||
200 | * @param string $compact_serialization |
||
201 | * @return IJWS |
||
202 | * @access private |
||
203 | */ |
||
204 | static public function fromCompactSerialization($compact_serialization) |
||
205 | { |
||
206 | list($header, $payload, $signature) = JWTSerializer::deserialize($compact_serialization); |
||
207 | return new JWS($header, JWSPayloadFactory::build($payload), $signature); |
||
208 | } |
||
209 | |||
210 | /** |
||
211 | * @return StringOrURI |
||
212 | */ |
||
213 | public function getSigningAlgorithm() |
||
214 | { |
||
215 | return $this->header->getAlgorithm(); |
||
216 | } |
||
217 | |||
218 | /** |
||
219 | * @return StringOrURI |
||
220 | */ |
||
221 | public function getType() |
||
222 | { |
||
223 | return $this->header->getType(); |
||
224 | } |
||
225 | |||
226 | /** |
||
227 | * @param string $original_alg |
||
228 | * @return bool |
||
229 | * @throws InvalidJWKAlgorithm |
||
230 | * @throws JWSInvalidJWKException |
||
231 | * @throws JWSInvalidPayloadException |
||
232 | * @throws JWSNotSupportedAlgorithm |
||
233 | */ |
||
234 | public function verify($original_alg) |
||
235 | { |
||
236 | if(is_null($this->jwk)) |
||
237 | throw new JWSInvalidJWKException; |
||
238 | |||
239 | View Code Duplication | if($this->jwk->getKeyUse()->getString() !== JSONWebKeyPublicKeyUseValues::Signature) |
|
240 | throw new JWSInvalidJWKException |
||
241 | ( |
||
242 | sprintf |
||
243 | ( |
||
244 | 'use %s not supported ', |
||
245 | $this->jwk->getKeyUse()->getString() |
||
246 | ) |
||
247 | ); |
||
248 | |||
249 | if(is_null($this->jwk->getAlgorithm())) |
||
250 | throw new InvalidJWKAlgorithm('algorithm intended for use with the key is not set! '); |
||
251 | |||
252 | if(!is_null($this->jwk->getId()) && !is_null($this->header->getKeyID()) && $this->header->getKeyID()->getValue() != $this->jwk->getId()->getValue()) |
||
253 | throw new JWSInvalidJWKException |
||
254 | ( |
||
255 | sprintf |
||
256 | ( |
||
257 | 'original kid %s - current kid %s', |
||
258 | $this->header->getKeyID()->getValue(), |
||
259 | $this->jwk->getId()->getValue() |
||
260 | ) |
||
261 | ); |
||
262 | |||
263 | $alg = DigitalSignatures_MACs_Registry::getInstance()->get($original_alg); |
||
264 | |||
265 | if(is_null($alg)) |
||
266 | throw new JWSNotSupportedAlgorithm(sprintf('algo %s', $original_alg)); |
||
267 | |||
268 | $former_alg = $this->header->getAlgorithm()->getString(); |
||
269 | |||
270 | if($former_alg != $original_alg) |
||
271 | throw new JWSNotSupportedAlgorithm |
||
272 | ( |
||
273 | sprintf |
||
274 | ( |
||
275 | 'former alg %s - original alg %s', |
||
276 | $former_alg, |
||
277 | $original_alg |
||
278 | ) |
||
279 | ); |
||
280 | |||
281 | if($this->jwk->getAlgorithm()->getValue() !== $original_alg) |
||
282 | throw new InvalidJWKAlgorithm |
||
283 | ( |
||
284 | sprintf |
||
285 | ( |
||
286 | 'mismatch between algorithm intended for use with the key %s and the cryptographic algorithm used to secure the JWS %s', |
||
287 | $this->jwk->getAlgorithm()->getValue(), |
||
288 | $original_alg |
||
289 | ) |
||
290 | ); |
||
291 | |||
292 | $secured_input_bytes = JOSEHeaderSerializer::serialize($this->header) . IBasicJWT::SegmentSeparator .$this->getEncodedPayload(); |
||
293 | |||
294 | // use public key / secret |
||
295 | $key = $this->jwk->getKey(JSONWebKeyKeyOperationsValues::VerifyDigitalSignatureOrMAC); |
||
296 | return $alg->verify($key, $secured_input_bytes, $this->signature); |
||
297 | } |
||
298 | |||
299 | /** |
||
300 | * @return IJWSPayloadSpec |
||
301 | */ |
||
302 | public function getPayload() |
||
303 | { |
||
304 | return $this->payload; |
||
305 | } |
||
306 | |||
307 | /** |
||
308 | * @param IJOSEHeader $header |
||
309 | * @param IJWSPayloadSpec $payload |
||
310 | * @param string $signature |
||
311 | * @return IJWS |
||
312 | */ |
||
313 | static public function fromHeaderClaimsAndSignature(IJOSEHeader $header, IJWSPayloadSpec $payload = null , $signature = '') |
||
314 | { |
||
315 | return new JWS($header, $payload, $signature ); |
||
316 | } |
||
317 | |||
318 | /** |
||
319 | * @return array |
||
320 | */ |
||
321 | public function take() |
||
322 | { |
||
323 | $payload = $this->payload->isClaimSet() ? $this->claim_set : $this->payload->getRaw(); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
jws\IJWSPayloadSpec as the method getRaw() does only exist in the following implementations of said interface: jws\payloads\_JWSPayloadRawSpec .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
Loading history...
|
|||
324 | |||
325 | return array |
||
326 | ( |
||
327 | $this->header, |
||
328 | $payload, |
||
329 | $this->signature |
||
330 | ); |
||
331 | } |
||
332 | } |
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVar
assignment in line 1 and the$higher
assignment in line 2 are dead. The first because$myVar
is never used and the second because$higher
is always overwritten for every possible time line.