Passed
Push — master ( fbb13e...d759f2 )
by Milad
02:55
created

AbstractEcdsaVerifier::algorithm()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace MiladRahimi\Jwt\Cryptography\Algorithms\Ecdsa;
4
5
use MiladRahimi\Jwt\Cryptography\Keys\EcdsaPublicKey;
6
use MiladRahimi\Jwt\Cryptography\Verifier;
7
use MiladRahimi\Jwt\Exceptions\InvalidSignatureException;
8
use function chr;
9
use function ltrim;
10
use function ord;
11
use function str_split;
12
use function strlen;
13
14
abstract class AbstractEcdsaVerifier implements Verifier
15
{
16
    use Algorithm;
17
18
    protected const ASN1_INTEGER = 0x02;
19
    protected const ASN1_SEQUENCE = 0x10;
20
21
    protected EcdsaPublicKey $publicKey;
22
23
    public function __construct(EcdsaPublicKey $key)
24
    {
25
        $this->publicKey = $key;
26
    }
27
28
    /**
29
     * @inheritdoc
30
     */
31
    public function verify(string $plain, string $signature): void
32
    {
33
        $signature = $this->signatureToDer($signature);
34
        if (openssl_verify($plain, $signature, $this->publicKey->getResource(), $this->algorithm()) !== 1) {
35
            throw new InvalidSignatureException(openssl_error_string() ?: "The signature is invalid.");
36
        }
37
    }
38
39
    protected function signatureToDer(string $signature): string
40
    {
41
        $length = max(1, (int)(strlen($signature) / 2));
42
        [$r, $s] = str_split($signature, $length);
43
44
        $r = ltrim($r, "\x00");
45
        $s = ltrim($s, "\x00");
46
47
        if (ord($r[0]) > 0x7f) {
48
            $r = "\x00" . $r;
49
        }
50
        if (ord($s[0]) > 0x7f) {
51
            $s = "\x00" . $s;
52
        }
53
54
        return $this->encodeDer(
55
            self::ASN1_SEQUENCE,
56
            $this->encodeDer(self::ASN1_INTEGER, $r) . $this->encodeDer(self::ASN1_INTEGER, $s),
57
        );
58
    }
59
60
    protected function encodeDer(int $type, string $value): string
61
    {
62
        $tagHeader = 0;
63
        if ($type === self::ASN1_SEQUENCE) {
64
            $tagHeader |= 0x20;
65
        }
66
67
        $der = chr($tagHeader | $type);
68
        $der .= chr(strlen($value));
69
70
        return $der . $value;
71
    }
72
73
    public function getPublicKey(): EcdsaPublicKey
74
    {
75
        return $this->publicKey;
76
    }
77
}
78