GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Branch php72 (880eb0)
by Joni
05:58
created

ECDSAAlgorithm   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 137
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 11
lcom 1
cbo 9
dl 0
loc 137
ccs 42
cts 42
cp 1
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 2
A computeSignature() 0 8 1
A headerParameters() 0 4 1
A fromPublicKey() 0 3 1
A fromPrivateKey() 0 3 1
A fromJWK() 0 11 3
A validateSignature() 0 12 2
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Sop\JWX\JWS\Algorithm;
6
7
use Sop\CryptoTypes\Asymmetric\EC\ECConversion;
8
use Sop\CryptoTypes\Signature\ECSignature;
9
use Sop\JWX\JWA\JWA;
10
use Sop\JWX\JWK\EC\ECPrivateKeyJWK;
11
use Sop\JWX\JWK\EC\ECPublicKeyJWK;
12
use Sop\JWX\JWK\JWK;
13
use Sop\JWX\JWS\SignatureAlgorithm;
14
use Sop\JWX\JWT\Header\Header;
15
use Sop\JWX\JWT\Parameter\AlgorithmParameter;
16
17
/**
18
 * Base class for algorithms implementing elliptic curve signature computation.
19
 *
20
 * @see https://tools.ietf.org/html/rfc7518#section-3.4
21
 */
22
abstract class ECDSAAlgorithm extends OpenSSLSignatureAlgorithm
23
{
24
    /**
25
     * Mapping from algorithm name to class name.
26
     *
27
     * @internal
28
     *
29
     * @var array
30
     */
31
    const MAP_ALGO_TO_CLASS = [
32
        JWA::ALGO_ES256 => ES256Algorithm::class,
33
        JWA::ALGO_ES384 => ES384Algorithm::class,
34
        JWA::ALGO_ES512 => ES512Algorithm::class,
35
    ];
36
37
    /**
38
     * Signature size in bytes.
39
     *
40
     * @var int
41
     */
42
    private $_signatureSize;
43
44
    /**
45
     * Constructor.
46
     *
47
     * @param ECPublicKeyJWK  $pub_key
48
     * @param ECPrivateKeyJWK $priv_key
49
     */
50 10
    protected function __construct(ECPublicKeyJWK $pub_key,
51
        ?ECPrivateKeyJWK $priv_key = null)
52
    {
53 10
        $curve = $pub_key->curveParameter()->value();
54 10
        if ($this->_curveName() !== $curve) {
55 1
            throw new \InvalidArgumentException(
56 1
                'Key with ' . $this->_curveName() .
57 1
                     " curve expected, got {$curve}.");
58
        }
59 9
        $this->_publicKey = $pub_key;
60 9
        $this->_privateKey = $priv_key;
61 9
        $key_size = $pub_key->curveParameter()->keySizeBits();
62 9
        $this->_signatureSize = intval(ceil($key_size / 8) * 2);
63 9
    }
64
65
    /**
66
     * Initialize from a public key.
67
     *
68
     * @param ECPublicKeyJWK $jwk
69
     *
70
     * @return self
71
     */
72 4
    public static function fromPublicKey(ECPublicKeyJWK $jwk): self
73
    {
74 4
        return new static($jwk);
75
    }
76
77
    /**
78
     * Initialize from a private key.
79
     *
80
     * @param ECPrivateKeyJWK $jwk
81
     *
82
     * @return self
83
     */
84 6
    public static function fromPrivateKey(ECPrivateKeyJWK $jwk): self
85
    {
86 6
        return new static($jwk->publicKey(), $jwk);
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     *
92
     * @return self
93
     */
94 6
    public static function fromJWK(JWK $jwk, Header $header): SignatureAlgorithm
95
    {
96 6
        $alg = JWA::deriveAlgorithmName($header, $jwk);
97 6
        if (!array_key_exists($alg, self::MAP_ALGO_TO_CLASS)) {
98 1
            throw new \UnexpectedValueException("Unsupported algorithm '{$alg}'.");
99
        }
100 5
        $cls = self::MAP_ALGO_TO_CLASS[$alg];
101 5
        if ($jwk->has(...ECPrivateKeyJWK::MANAGED_PARAMS)) {
102 3
            return $cls::fromPrivateKey(ECPrivateKeyJWK::fromJWK($jwk));
103
        }
104 2
        return $cls::fromPublicKey(ECPublicKeyJWK::fromJWK($jwk));
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110 4
    public function computeSignature(string $data): string
111
    {
112
        // OpenSSL returns ECDSA signature as a DER encoded ECDSA-Sig-Value
113 4
        $der = parent::computeSignature($data);
114 4
        $sig = ECSignature::fromDER($der);
115 4
        $mlen = intval(floor($this->_signatureSize / 2));
116 4
        return ECConversion::numberToOctets($sig->r(), $mlen) .
117 4
             ECConversion::numberToOctets($sig->s(), $mlen);
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     *
123
     * @throws \UnexpectedValueException If signature length is invalid
124
     */
125 5
    public function validateSignature(string $data, string $signature): bool
126
    {
127 5
        if (strlen($signature) !== $this->_signatureSize) {
128 1
            throw new \UnexpectedValueException('Invalid signature length.');
129
        }
130 4
        [$r_octets, $s_octets] = str_split($signature,
131 4
            intval(floor($this->_signatureSize / 2)));
132
        // convert signature to DER sequence for OpenSSL
133 4
        $r = ECConversion::octetsToNumber($r_octets);
134 4
        $s = ECConversion::octetsToNumber($s_octets);
135 4
        $sig = new ECSignature($r, $s);
136 4
        return parent::validateSignature($data, $sig->toDER());
137
    }
138
139
    /**
140
     * {@inheritdoc}
141
     */
142 2
    public function headerParameters(): array
143
    {
144 2
        return array_merge(parent::headerParameters(),
145 2
            [AlgorithmParameter::fromAlgorithm($this)]);
146
    }
147
148
    /**
149
     * Get the name of the curve used by this algorithm.
150
     *
151
     * @return string
152
     */
153
    abstract protected function _curveName(): string;
154
}
155