Completed
Push — v2.0.x ( 8e74ea...23a51c )
by Florent
02:24
created

Verifier::checkSignaturess()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 6
rs 9.4285
cc 2
eloc 3
nc 2
nop 1
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\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
        $this->checkPayload($jws, $detached_payload);
69
        $this->checkJWKSet($jwk_set);
70
        $this->checkSignaturess($jws);
71
72
        for ($i = 0; $i < $jws->countSignatures(); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
Consider avoiding function calls on each iteration of the for loop.

If you have a function call in the test part of a for loop, this function is executed on each iteration. Often such a function, can be moved to the initialization part and be cached.

// count() is called on each iteration
for ($i=0; $i < count($collection); $i++) { }

// count() is only called once
for ($i=0, $c=count($collection); $i<$c; $i++) { }
Loading history...
73
            $signature = $jws->getSignature($i);
74
            $input = $signature->getEncodedProtectedHeaders().'.'.(null === $detached_payload ? $jws->getEncodedPayload() : $detached_payload);
75
76
            foreach ($jwk_set->getKeys() as $jwk) {
77
                $algorithm = $this->getAlgorithm($signature);
78
                try {
79
                    $this->checkKeyUsage($jwk, 'verification');
80
                    $this->checkKeyAlgorithm($jwk, $algorithm->getAlgorithmName());
81
                    if (true === $algorithm->verify($jwk, $input, $signature->getSignature())) {
82
                        $this->getCheckerManager()->checkJWT($jws);
83
84
                        return $i;
85
                    }
86
                } catch (\Exception $e) {
87
                    //We do nothing, we continue with other keys
88
                    continue;
89
                }
90
            }
91
        }
92
93
        return false;
94
    }
95
96
    /**
97
     * @param \Jose\Object\JWSInterface $jws
98
     */
99
    private function checkSignaturess(JWSInterface $jws)
100
    {
101
        if (0 === $jws->countSignatures()) {
102
            throw new \InvalidArgumentException('The JWS does not contain any signature.');
103
        }
104
    }
105
106
    /**
107
     * @param \Jose\Object\JWKSetInterface $jwk_set
108
     */
109
    private function checkJWKSet(JWKSetInterface $jwk_set)
110
    {
111
        if (0 === count($jwk_set)) {
112
            throw new \InvalidArgumentException('No key in the key set.');
113
        }
114
    }
115
116
    /**
117
     * @param \Jose\Object\JWSInterface $jws
118
     * @param null|string               $detached_payload
119
     */
120
    private function checkPayload(JWSInterface $jws, $detached_payload = null)
121
    {
122
        if (null !== $detached_payload && !empty($jws->getEncodedPayload())) {
123
            throw new \InvalidArgumentException('A detached payload is set, but the JWS already has a payload.');
124
        }
125
    }
126
127
    /**
128
     * @param \Jose\Object\SignatureInterface $signature
129
     *
130
     * @return \Jose\Algorithm\SignatureAlgorithmInterface|null
131
     */
132
    private function getAlgorithm(SignatureInterface $signature)
133
    {
134
        $complete_headers = array_merge(
135
            $signature->getProtectedHeaders(),
136
            $signature->getHeaders()
137
        );
138
        if (!array_key_exists('alg', $complete_headers)) {
139
            throw new \InvalidArgumentException('No "alg" parameter set in the header.');
140
        }
141
142
        $algorithm = $this->getJWAManager()->getAlgorithm($complete_headers['alg']);
143
        if (!$algorithm instanceof SignatureAlgorithmInterface) {
144
            throw new \RuntimeException(sprintf('The algorithm "%s" is not supported or does not implement SignatureInterface.', $complete_headers['alg']));
145
        }
146
147
        return $algorithm;
148
    }
149
}
150