Completed
Push — master ( c2da0b...c79410 )
by Florent
06:52 queued 04:00
created

Signer::computeSignature()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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