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.

ECDSAAlgorithm   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 11
eloc 39
dl 0
loc 121
ccs 41
cts 41
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
    public 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 ECPrivateKeyJWK $priv_key
48
     */
49 10
    protected function __construct(ECPublicKeyJWK $pub_key,
50
        ?ECPrivateKeyJWK $priv_key = null)
51
    {
52 10
        $curve = $pub_key->curveParameter()->value();
53 10
        if ($this->_curveName() !== $curve) {
54 1
            throw new \InvalidArgumentException(
55 1
                'Key with ' . $this->_curveName() .
56 1
                     " curve expected, got {$curve}.");
57
        }
58 9
        $this->_publicKey = $pub_key;
59 9
        $this->_privateKey = $priv_key;
60 9
        $key_size = $pub_key->curveParameter()->keySizeBits();
61 9
        $this->_signatureSize = intval(ceil($key_size / 8) * 2);
62 9
    }
63
64
    /**
65
     * Initialize from a public key.
66
     */
67 4
    public static function fromPublicKey(ECPublicKeyJWK $jwk): self
68
    {
69 4
        return new static($jwk);
70
    }
71
72
    /**
73
     * Initialize from a private key.
74
     */
75 6
    public static function fromPrivateKey(ECPrivateKeyJWK $jwk): self
76
    {
77 6
        return new static($jwk->publicKey(), $jwk);
78
    }
79
80
    /**
81
     * {@inheritdoc}
82
     *
83
     * @return self
84
     */
85 6
    public static function fromJWK(JWK $jwk, Header $header): SignatureAlgorithm
86
    {
87 6
        $alg = JWA::deriveAlgorithmName($header, $jwk);
88 6
        if (!array_key_exists($alg, self::MAP_ALGO_TO_CLASS)) {
89 1
            throw new \UnexpectedValueException("Unsupported algorithm '{$alg}'.");
90
        }
91 5
        $cls = self::MAP_ALGO_TO_CLASS[$alg];
92 5
        if ($jwk->has(...ECPrivateKeyJWK::MANAGED_PARAMS)) {
93 3
            return $cls::fromPrivateKey(ECPrivateKeyJWK::fromJWK($jwk));
94
        }
95 2
        return $cls::fromPublicKey(ECPublicKeyJWK::fromJWK($jwk));
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101 4
    public function computeSignature(string $data): string
102
    {
103
        // OpenSSL returns ECDSA signature as a DER encoded ECDSA-Sig-Value
104 4
        $der = parent::computeSignature($data);
105 4
        $sig = ECSignature::fromDER($der);
106 4
        $mlen = intval(floor($this->_signatureSize / 2));
107 4
        return ECConversion::numberToOctets($sig->r(), $mlen) .
108 4
             ECConversion::numberToOctets($sig->s(), $mlen);
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     *
114
     * @throws \UnexpectedValueException If signature length is invalid
115
     */
116 5
    public function validateSignature(string $data, string $signature): bool
117
    {
118 5
        if (strlen($signature) !== $this->_signatureSize) {
119 1
            throw new \UnexpectedValueException('Invalid signature length.');
120
        }
121 4
        [$r_octets, $s_octets] = str_split($signature,
122 4
            intval(floor($this->_signatureSize / 2)));
123
        // convert signature to DER sequence for OpenSSL
124 4
        $r = ECConversion::octetsToNumber($r_octets);
125 4
        $s = ECConversion::octetsToNumber($s_octets);
126 4
        $sig = new ECSignature($r, $s);
127 4
        return parent::validateSignature($data, $sig->toDER());
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133 2
    public function headerParameters(): array
134
    {
135 2
        return array_merge(parent::headerParameters(),
136 2
            [AlgorithmParameter::fromAlgorithm($this)]);
137
    }
138
139
    /**
140
     * Get the name of the curve used by this algorithm.
141
     */
142
    abstract protected function _curveName(): string;
143
}
144