Completed
Push — v2.0.x ( 59a3d4...b06cab )
by Florent
03:22
created

Verifier::verifyWithKeySet()   D

Complexity

Conditions 9
Paths 15

Size

Total Lines 28
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 2 Features 0
Metric Value
c 2
b 2
f 0
dl 0
loc 28
rs 4.909
cc 9
eloc 17
nc 15
nop 3
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
        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
                try {
80
                    $this->checkKeyUsage($jwk, 'verification');
81
                    $this->checkKeyAlgorithm($jwk, $algorithm->getAlgorithmName());
82
                    if (true === $algorithm->verify($jwk, $input, $signature->getSignature())) {
83
                        return true;
84
                    }
85
                } catch (\Exception $e) {
86
                    //We do nothing, we continue with other keys
87
                    continue;
88
                }
89
            }
90
        }
91
92
        return false;
93
    }
94
95
    /**
96
     * @param \Jose\Object\SignatureInterface $signature
97
     *
98
     * @return \Jose\Algorithm\SignatureAlgorithmInterface|null
99
     */
100
    private function getAlgorithm(SignatureInterface $signature)
101
    {
102
        $complete_headers = array_merge(
103
            $signature->getProtectedHeaders(),
104
            $signature->getHeaders()
105
        );
106
        if (!array_key_exists('alg', $complete_headers)) {
107
            throw new \InvalidArgumentException('No "alg" parameter set in the header.');
108
        }
109
110
        $algorithm = $this->getJWAManager()->getAlgorithm($complete_headers['alg']);
111
        if (!$algorithm instanceof SignatureAlgorithmInterface) {
112
            throw new \RuntimeException(sprintf('The algorithm "%s" is not supported or does not implement SignatureInterface.', $complete_headers['alg']));
113
        }
114
115
        return $algorithm;
116
    }
117
}
118