Completed
Branch develop (8ddc4a)
by Florent
02:46
created

Signer::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 9
rs 9.6666
cc 2
eloc 5
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\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\SignatureInterface;
23
use Psr\Log\LoggerInterface;
24
use Psr\Log\LogLevel;
25
26
/**
27
 */
28
final class Signer implements SignerInterface
29
{
30
    use HasKeyChecker;
31
    use HasJWAManager;
32
    use HasLogger;
33
34
    /**
35
     * Signer constructor.
36
     *
37
     * @param \Jose\Algorithm\JWAManagerInterface $jwa_manager
38
     * @param \Psr\Log\LoggerInterface|null       $logger
39
     */
40
    public function __construct(JWAManagerInterface $jwa_manager,
41
                                LoggerInterface $logger = null
42
    ) {
43
        $this->setJWAManager($jwa_manager);
44
45
        if (null !== $logger) {
46
            $this->setLogger($logger);
47
        }
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public function signWithDetachedPayload(JWSInterface &$jws, $detached_payload)
54
    {
55
        $this->log(LogLevel::INFO, 'Trying to sign the JWS object with detached payload', ['jws' => $jws, 'payload' => $detached_payload]);
56
57
        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...
58
            $this->computeSignature($detached_payload, $jws->getSignature($i));
0 ignored issues
show
Bug introduced by
$jws->getSignature($i) cannot be passed to computesignature() as the parameter $signature expects a reference.
Loading history...
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
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
            $this->computeSignature($jws->getEncodedPayload(), $jws->getSignature($i));
0 ignored issues
show
Bug introduced by
$jws->getSignature($i) cannot be passed to computesignature() as the parameter $signature expects a reference.
Loading history...
74
        }
75
        $this->log(LogLevel::INFO, 'Signature added');
76
    }
77
78
    /**
79
     * @param string                          $payload
80
     * @param \Jose\Object\SignatureInterface $signature
81
     */
82
    private function computeSignature($payload, SignatureInterface &$signature)
83
    {
84
        $this->log(LogLevel::DEBUG, 'Creation of the signature');
85
        $this->checkKeyUsage($signature->getSignatureKey(), 'signature');
86
87
        $signature_algorithm = $this->getSignatureAlgorithm($signature->getAllHeaders(), $signature->getSignatureKey());
88
89
        $this->log(LogLevel::DEBUG, 'Trying to compute the signature');
90
        $value = $signature_algorithm->sign($signature->getSignatureKey(), $signature->getEncodedProtectedHeaders().'.'.$payload);
91
        $this->log(LogLevel::DEBUG, 'Signature computation done');
92
93
        $signature = $signature->withSignature($value);
94
95
        $this->log(LogLevel::DEBUG, 'The signature is done', ['signature' => $signature]);
96
    }
97
98
    /**
99
     * @param array                     $complete_header The complete header
100
     * @param \Jose\Object\JWKInterface $key
101
     *
102
     * @return \Jose\Algorithm\SignatureAlgorithmInterface
103
     */
104
    private function getSignatureAlgorithm(array $complete_header, JWKInterface $key)
105
    {
106
        $this->log(LogLevel::DEBUG, 'Trying to find the algorithm used to sign');
107
        Assertion::keyExists($complete_header, 'alg', 'No "alg" parameter set in the header.');
108
109
        $this->log(LogLevel::DEBUG, 'The algorithm is {alg}', ['alg' => $complete_header['alg']]);
110
111
        Assertion::false(
112
            $key->has('alg') && $key->get('alg') !== $complete_header['alg'],
113
            sprintf('The algorithm "%s" is allowed with this key.', $complete_header['alg'])
114
        );
115
116
117
        $signature_algorithm = $this->getJWAManager()->getAlgorithm($complete_header['alg']);
118
        Assertion::isInstanceOf($signature_algorithm, SignatureAlgorithmInterface::class, sprintf('The algorithm "%s" is not supported.', $complete_header['alg']));
119
120
        $this->log(LogLevel::DEBUG, 'The algorithm {alg} is supported', ['alg' => $complete_header['alg'], 'handler' => $signature_algorithm]);
121
122
        return $signature_algorithm;
123
    }
124
}
125