Completed
Push — master ( 1a59c2...c73113 )
by Florent
02:55
created

Signer   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 106
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 12
Bugs 6 Features 1
Metric Value
wmc 10
c 12
b 6
f 1
lcom 1
cbo 9
dl 0
loc 106
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 2
A signWithDetachedPayload() 0 11 2
A sign() 0 11 2
A computeSignature() 0 23 2
A getSignatureAlgorithm() 0 19 2
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 Assert\Assertion;
15
use Jose\Algorithm\JWAManagerInterface;
16
use Jose\Algorithm\SignatureAlgorithmInterface;
17
use Jose\Behaviour\HasJWAManager;
18
use Jose\Behaviour\HasKeyChecker;
19
use Jose\Behaviour\HasLogger;
20
use Jose\Object\JWKInterface;
21
use Jose\Object\JWSInterface;
22
use Jose\Object\Signature;
23
use Jose\Object\SignatureInterface;
24
use Psr\Log\LoggerInterface;
25
use Psr\Log\LogLevel;
26
27
final class Signer implements SignerInterface
28
{
29
    use HasKeyChecker;
30
    use HasJWAManager;
31
    use HasLogger;
32
33
    /**
34
     * Signer constructor.
35
     *
36
     * @param \Jose\Algorithm\JWAManagerInterface $jwa_manager
37
     * @param \Psr\Log\LoggerInterface|null       $logger
38
     */
39
    public function __construct(JWAManagerInterface $jwa_manager,
40
                                LoggerInterface $logger = null
41
    ) {
42
        $this->setJWAManager($jwa_manager);
43
44
        if (null !== $logger) {
45
            $this->setLogger($logger);
46
        }
47
    }
48
49
    /**
50
     * {@inheritdoc}
51
     */
52
    public function signWithDetachedPayload(JWSInterface &$jws, $detached_payload)
53
    {
54
        $this->log(LogLevel::INFO, 'Trying to sign the JWS object with detached payload', ['jws' => $jws, 'payload' => $detached_payload]);
55
        $nb_signatures = $jws->countSignatures();
56
        
57
        for ($i = 0; $i < $nb_signatures; $i++) {
58
            $this->computeSignature($detached_payload, $jws->getSignature($i));
59
        }
60
61
        $this->log(LogLevel::INFO, 'Signature added');
62
    }
63
64
    /**
65
     * {@inheritdoc}
66
     */
67
    public function sign(JWSInterface &$jws)
68
    {
69
        $this->log(LogLevel::INFO, 'Trying to sign the JWS object', ['jws' => $jws]);
70
        Assertion::notNull($jws->getEncodedPayload(), 'No payload.');
71
        $nb_signatures = $jws->countSignatures();
72
73
        for ($i = 0; $i < $nb_signatures; $i++) {
74
            $this->computeSignature($jws->getEncodedPayload(), $jws->getSignature($i));
75
        }
76
        $this->log(LogLevel::INFO, 'JWS object signed!');
77
    }
78
79
    /**
80
     * @param string                          $payload
81
     * @param \Jose\Object\SignatureInterface $signature
82
     */
83
    private function computeSignature($payload, SignatureInterface &$signature)
84
    {
85
        $this->log(LogLevel::DEBUG, 'Creation of the signature');
86
        if (null === $signature->getSignatureKey()) {
87
            $this->log(LogLevel::DEBUG, 'The signature key is not set. Aborting.');
88
            return;
89
        }
90
        $this->checkKeyUsage($signature->getSignatureKey(), 'signature');
91
92
        $signature_algorithm = $this->getSignatureAlgorithm($signature->getAllHeaders(), $signature->getSignatureKey());
93
94
        $this->log(LogLevel::DEBUG, 'Trying to compute the signature');
95
        $value = $signature_algorithm->sign($signature->getSignatureKey(), $signature->getEncodedProtectedHeaders().'.'.$payload);
96
        $this->log(LogLevel::DEBUG, 'Signature computation done');
97
98
        $signature = Signature::createSignatureFromLoadedData(
99
            $value,
100
            $signature->getEncodedProtectedHeaders(),
101
            $signature->getHeaders()
102
        );
103
104
        $this->log(LogLevel::DEBUG, 'The signature is done', ['signature' => $signature]);
105
    }
106
107
    /**
108
     * @param array                     $complete_header The complete header
109
     * @param \Jose\Object\JWKInterface $key
110
     *
111
     * @return \Jose\Algorithm\SignatureAlgorithmInterface
112
     */
113
    private function getSignatureAlgorithm(array $complete_header, JWKInterface $key)
114
    {
115
        $this->log(LogLevel::DEBUG, 'Trying to find the algorithm used to sign');
116
        Assertion::keyExists($complete_header, 'alg', 'No "alg" parameter set in the header.');
117
118
        $this->log(LogLevel::DEBUG, 'The algorithm is {alg}', ['alg' => $complete_header['alg']]);
119
120
        Assertion::false(
121
            $key->has('alg') && $key->get('alg') !== $complete_header['alg'],
122
            sprintf('The algorithm "%s" is not allowed with this key.', $complete_header['alg'])
123
        );
124
125
        $signature_algorithm = $this->getJWAManager()->getAlgorithm($complete_header['alg']);
126
        Assertion::isInstanceOf($signature_algorithm, SignatureAlgorithmInterface::class, sprintf('The algorithm "%s" is not supported.', $complete_header['alg']));
127
128
        $this->log(LogLevel::DEBUG, 'The algorithm {alg} is supported', ['alg' => $complete_header['alg'], 'handler' => $signature_algorithm]);
129
130
        return $signature_algorithm;
131
    }
132
}
133