File: EcdsaTestCase.php

package info (click to toggle)
php-lcobucci-jwt 5.6.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,312 kB
  • sloc: php: 6,674; makefile: 49
file content (151 lines) | stat: -rw-r--r-- 4,563 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<?php
declare(strict_types=1);

namespace Lcobucci\JWT\Tests\Signer\Ecdsa;

use Lcobucci\JWT\Signer\Ecdsa;
use Lcobucci\JWT\Signer\Ecdsa\MultibyteStringConverter;
use Lcobucci\JWT\Signer\InvalidKeyProvided;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Tests\Keys;
use OpenSSLAsymmetricKey;
use PHPUnit\Framework\Attributes as PHPUnit;
use PHPUnit\Framework\TestCase;

use function assert;
use function openssl_error_string;
use function openssl_pkey_get_private;
use function openssl_pkey_get_public;
use function openssl_sign;
use function openssl_verify;

abstract class EcdsaTestCase extends TestCase
{
    use Keys;

    protected MultibyteStringConverter $pointsManipulator;

    #[PHPUnit\After]
    final public function clearOpenSSLErrors(): void
    {
        // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedWhile
        while (openssl_error_string()) {
        }
    }

    #[PHPUnit\Before]
    final public function createDependencies(): void
    {
        $this->pointsManipulator = new MultibyteStringConverter();
    }

    abstract protected function algorithm(): Ecdsa;

    abstract protected function algorithmId(): string;

    abstract protected function signatureAlgorithm(): int;

    abstract protected function pointLength(): int;

    abstract protected function keyLength(): int;

    abstract protected function verificationKey(): Key;

    abstract protected function signingKey(): Key;

    #[PHPUnit\Test]
    final public function algorithmIdMustBeCorrect(): void
    {
        self::assertSame($this->algorithmId(), $this->algorithm()->algorithmId());
    }

    #[PHPUnit\Test]
    final public function signatureAlgorithmMustBeCorrect(): void
    {
        self::assertSame($this->signatureAlgorithm(), $this->algorithm()->algorithm());
    }

    #[PHPUnit\Test]
    final public function pointLengthMustBeCorrect(): void
    {
        self::assertSame($this->pointLength(), $this->algorithm()->pointLength());
    }

    #[PHPUnit\Test]
    final public function expectedKeyLengthMustBeCorrect(): void
    {
        self::assertSame($this->keyLength(), $this->algorithm()->expectedKeyLength());
    }

    #[PHPUnit\Test]
    public function signShouldReturnTheAHashBasedOnTheOpenSslSignature(): void
    {
        $payload = 'testing';

        $signer    = $this->algorithm();
        $signature = $signer->sign($payload, $this->signingKey());

        $publicKey = openssl_pkey_get_public($this->verificationKey()->contents());
        assert($publicKey instanceof OpenSSLAsymmetricKey);

        self::assertSame(
            1,
            openssl_verify(
                $payload,
                $this->pointsManipulator->toAsn1($signature, $signer->pointLength()),
                $publicKey,
                $this->signatureAlgorithm(),
            ),
        );
    }

    #[PHPUnit\Test]
    #[PHPUnit\DataProvider('incompatibleKeys')]
    public function signShouldRaiseAnExceptionWhenKeyLengthIsNotTheExpectedOne(
        string $keyId,
        int $keyLength,
    ): void {
        self::assertArrayHasKey($keyId, self::$ecdsaKeys);

        $this->expectException(InvalidKeyProvided::class);
        $this->expectExceptionMessage(
            'The length of the provided key is different than ' . $this->keyLength()
            . ' bits, ' . $keyLength . ' bits provided',
        );

        $this->algorithm()->sign('testing', self::$ecdsaKeys[$keyId]);
    }

    /** @return iterable<string, array{string, int}> */
    abstract public static function incompatibleKeys(): iterable;

    #[PHPUnit\Test]
    public function signShouldRaiseAnExceptionWhenKeyTypeIsNotEC(): void
    {
        $this->expectException(InvalidKeyProvided::class);
        $this->expectExceptionMessage('The type of the provided key is not "EC", "RSA" provided');

        $this->algorithm()->sign('testing', self::$rsaKeys['private']);
    }

    #[PHPUnit\Test]
    public function verifyShouldDelegateToEcdsaSignerUsingPublicKey(): void
    {
        $payload    = 'testing';
        $privateKey = openssl_pkey_get_private($this->signingKey()->contents());
        assert($privateKey instanceof OpenSSLAsymmetricKey);

        $signature = '';
        openssl_sign($payload, $signature, $privateKey, $this->signatureAlgorithm());

        $signer = $this->algorithm();

        self::assertTrue(
            $signer->verify(
                $this->pointsManipulator->fromAsn1($signature, $signer->pointLength()),
                $payload,
                $this->verificationKey(),
            ),
        );
    }
}