Completed
Push — v2.0.x ( be7995...de999d )
by Florent
25:30 queued 10:49
created

Verifier::verify()   C

Complexity

Conditions 11
Paths 15

Size

Total Lines 33
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 9
Bugs 4 Features 1
Metric Value
c 9
b 4
f 1
dl 0
loc 33
rs 5.2653
cc 11
eloc 19
nc 15
nop 3

1 Method

Rating   Name   Duplication   Size   Complexity  
A Verifier::verifyWithKey() 0 7 1

How to fix   Complexity   

Long Method

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:

1
<?php
2
3
/*
4
 * The MIT License (MIT)
5
 *
6
 * Copyright (c) 2014-2015 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\Algorithm\JWAManagerInterface;
15
use Jose\Algorithm\SignatureAlgorithmInterface;
16
use Jose\Behaviour\HasCheckerManager;
17
use Jose\Behaviour\HasJWAManager;
18
use Jose\Behaviour\HasKeyChecker;
19
use Jose\Checker\CheckerManagerInterface;
20
use Jose\Object\JWKInterface;
21
use Jose\Object\JWKSet;
22
use Jose\Object\JWKSetInterface;
23
use Jose\Object\JWSInterface;
24
use Jose\Object\SignatureInterface;
25
26
/**
27
 */
28
final class Verifier implements VerifierInterface
29
{
30
    use HasKeyChecker;
31
    use HasJWAManager;
32
    use HasCheckerManager;
33
34
    /**
35
     * Loader constructor.
36
     *
37
     * @param \Jose\Algorithm\JWAManagerInterface   $jwa_manager
38
     * @param \Jose\Checker\CheckerManagerInterface $checker_manager
39
     */
40
    public function __construct(
41
        JWAManagerInterface $jwa_manager,
42
        CheckerManagerInterface $checker_manager)
43
    {
44
        $this->setJWAManager($jwa_manager);
45
        $this->setCheckerManager($checker_manager);
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     *
51
     * @throws \InvalidArgumentException
52
     */
53
    public function verifyWithKey(JWSInterface $jws, JWKInterface $jwk, $detached_payload = null)
54
    {
55
        $jwk_set = new JWKSet();
56
        $jwk_set = $jwk_set->addKey($jwk);
57
58
        return $this->verifyWithKeySet($jws, $jwk_set, $detached_payload);
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     *
64
     * @throws \InvalidArgumentException
65
     */
66
    public function verifyWithKeySet(JWSInterface $jws, JWKSetInterface $jwk_set, $detached_payload = null)
67
    {
68
        if (null !== $detached_payload && !empty($jws->getEncodedPayload())) {
69
            throw new \InvalidArgumentException('A detached payload is set, but the JWS already has a payload.');
70
        }
71
        if (0 === count($jwk_set)) {
72
            throw new \InvalidArgumentException('No key in the key set.');
73
        }
74
        foreach ($jws->getSignatures() as $signature) {
75
            $input = $signature->getEncodedProtectedHeaders().'.'.(null === $detached_payload ? $jws->getEncodedPayload() : $detached_payload);
76
77
            foreach ($jwk_set->getKeys() as $jwk) {
78
                $algorithm = $this->getAlgorithm($signature);
79
                if (!$this->checkKeyUsage($jwk, 'verification')) {
80
                    continue;
81
                }
82
                if (!$this->checkKeyAlgorithm($jwk, $algorithm->getAlgorithmName())) {
83
                    continue;
84
                }
85
                try {
86
                    if (true === $algorithm->verify($jwk, $input, $signature->getSignature())) {
87
                        return true;
88
                    }
89
                } catch (\Exception $e) {
90
                    //We do nothing, we continue with other keys
91
                    continue;
92
                }
93
            }
94
        }
95
96
97
        return false;
98
    }
99
100
    /**
101
     * @param \Jose\Object\SignatureInterface $signature
102
     *
103
     * @return \Jose\Algorithm\SignatureAlgorithmInterface|null
104
     */
105
    private function getAlgorithm(SignatureInterface $signature)
106
    {
107
        $complete_headers = array_merge(
108
            $signature->getProtectedHeaders(),
109
            $signature->getHeaders()
110
        );
111
        if (!array_key_exists('alg', $complete_headers)) {
112
            throw new \InvalidArgumentException('No "alg" parameter set in the header.');
113
        }
114
115
        $algorithm = $this->getJWAManager()->getAlgorithm($complete_headers['alg']);
116
        if (!$algorithm instanceof SignatureAlgorithmInterface) {
117
            throw new \RuntimeException(sprintf('The algorithm "%s" is not supported or does not implement SignatureInterface.', $complete_headers['alg']));
118
        }
119
120
        return $algorithm;
121
    }
122
}
123