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

RSAESKeyAlgorithm::_encryptKey()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 17
ccs 12
cts 12
cp 1
rs 9.8333
c 0
b 0
f 0
cc 3
nc 3
nop 2
crap 3
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Sop\JWX\JWE\KeyAlgorithm;
6
7
use Sop\JWX\JWA\JWA;
8
use Sop\JWX\JWE\KeyAlgorithm\Feature\RandomCEK;
9
use Sop\JWX\JWE\KeyManagementAlgorithm;
10
use Sop\JWX\JWK\JWK;
11
use Sop\JWX\JWK\RSA\RSAPrivateKeyJWK;
12
use Sop\JWX\JWK\RSA\RSAPublicKeyJWK;
13
use Sop\JWX\JWT\Header\Header;
14
use Sop\JWX\JWT\Parameter\AlgorithmParameter;
15
16
/**
17
 * Base class for algorithms implementing RSA based key encryption.
18
 *
19
 * @see https://tools.ietf.org/html/rfc7518#section-4.2
20
 * @see https://tools.ietf.org/html/rfc7518#section-4.3
21
 */
22
abstract class RSAESKeyAlgorithm extends KeyManagementAlgorithm
23
{
24
    use RandomCEK;
25
26
    /**
27
     * Mapping from algorithm name to class name.
28
     *
29
     * @internal
30
     *
31
     * @var array
32
     */
33
    const MAP_ALGO_TO_CLASS = [
34
        JWA::ALGO_RSA1_5 => RSAESPKCS1Algorithm::class,
35
        JWA::ALGO_RSA_OAEP => RSAESOAEPAlgorithm::class,
36
    ];
37
38
    /**
39
     * Public key.
40
     *
41
     * @var RSAPublicKeyJWK
42
     */
43
    protected $_publicKey;
44
45
    /**
46
     * Private key.
47
     *
48
     * @var null|RSAPrivateKeyJWK
49
     */
50
    protected $_privateKey;
51
52
    /**
53
     * Constructor.
54
     *
55
     * Use <code>fromPublicKey</code> or <code>fromPrivateKey</code> instead!
56
     *
57
     * @param RSAPublicKeyJWK  $pub_key  RSA public key
58
     * @param RSAPrivateKeyJWK $priv_key Optional RSA private key
59
     */
60 18
    protected function __construct(RSAPublicKeyJWK $pub_key,
61
        ?RSAPrivateKeyJWK $priv_key = null)
62
    {
63 18
        $this->_publicKey = $pub_key;
64 18
        $this->_privateKey = $priv_key;
65 18
    }
66
67
    /**
68
     * Initialize from JWK.
69
     *
70
     * @param JWK    $jwk
71
     * @param Header $header
72
     *
73
     * @throws \UnexpectedValueException
74
     *
75
     * @return self
76
     */
77 3
    public static function fromJWK(JWK $jwk, Header $header): KeyManagementAlgorithm
78
    {
79 3
        $alg = JWA::deriveAlgorithmName($header, $jwk);
80 3
        if (!array_key_exists($alg, self::MAP_ALGO_TO_CLASS)) {
81 1
            throw new \UnexpectedValueException("Unsupported algorithm '{$alg}'.");
82
        }
83 2
        $cls = self::MAP_ALGO_TO_CLASS[$alg];
84 2
        if ($jwk->has(...RSAPrivateKeyJWK::MANAGED_PARAMS)) {
85 1
            return $cls::fromPrivateKey(RSAPrivateKeyJWK::fromJWK($jwk));
86
        }
87 1
        return $cls::fromPublicKey(RSAPublicKeyJWK::fromJWK($jwk));
88
    }
89
90
    /**
91
     * Initialize from a public key.
92
     *
93
     * @param RSAPublicKeyJWK $jwk
94
     *
95
     * @return self
96
     */
97 3
    public static function fromPublicKey(RSAPublicKeyJWK $jwk): self
98
    {
99 3
        return new static($jwk);
100
    }
101
102
    /**
103
     * Initialize from a private key.
104
     *
105
     * @param RSAPrivateKeyJWK $jwk
106
     *
107
     * @return self
108
     */
109 15
    public static function fromPrivateKey(RSAPrivateKeyJWK $jwk): self
110
    {
111 15
        return new static($jwk->publicKey(), $jwk);
112
    }
113
114
    /**
115
     * Get the public key.
116
     *
117
     * @return RSAPublicKeyJWK
118
     */
119 11
    public function publicKey(): RSAPublicKeyJWK
120
    {
121 11
        return $this->_publicKey;
122
    }
123
124
    /**
125
     * Check whether the private key is present.
126
     *
127
     * @return bool
128
     */
129 13
    public function hasPrivateKey(): bool
130
    {
131 13
        return isset($this->_privateKey);
132
    }
133
134
    /**
135
     * Get the private key.
136
     *
137
     * @throws \LogicException
138
     *
139
     * @return RSAPrivateKeyJWK
140
     */
141 12
    public function privateKey(): RSAPrivateKeyJWK
142
    {
143 12
        if (!$this->hasPrivateKey()) {
144 1
            throw new \LogicException('Private key not set.');
145
        }
146 11
        return $this->_privateKey;
1 ignored issue
show
Bug Best Practice introduced by
The expression return $this->_privateKey could return the type null which is incompatible with the type-hinted return Sop\JWX\JWK\RSA\RSAPrivateKeyJWK. Consider adding an additional type-check to rule them out.
Loading history...
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152 3
    public function headerParameters(): array
153
    {
154 3
        return array_merge(parent::headerParameters(),
155 3
            [AlgorithmParameter::fromAlgorithm($this)]);
156
    }
157
158
    /**
159
     * Get the padding scheme.
160
     *
161
     * @return int
162
     */
163
    abstract protected function _paddingScheme(): int;
164
165
    /**
166
     * {@inheritdoc}
167
     */
168 10
    protected function _encryptKey(string $key, Header &$header): string
169
    {
170 10
        $pubkey = openssl_pkey_get_public(
171 10
            $this->publicKey()->toPEM()->string());
172 10
        if (false === $pubkey) {
173 1
            throw new \RuntimeException(
174
                'openssl_pkey_get_public() failed: ' .
175 1
                     $this->_getLastOpenSSLError());
176
        }
177 9
        $result = openssl_public_encrypt($key, $crypted, $pubkey,
178 9
            $this->_paddingScheme());
179 9
        if (!$result) {
180 1
            throw new \RuntimeException(
181
                'openssl_public_encrypt() failed: ' .
182 1
                     $this->_getLastOpenSSLError());
183
        }
184 8
        return $crypted;
185
    }
186
187
    /**
188
     * {@inheritdoc}
189
     */
190 10
    protected function _decryptKey(string $ciphertext, Header $header): string
191
    {
192 10
        $privkey = openssl_pkey_get_private(
193 10
            $this->privateKey()->toPEM()->string());
194 10
        if (false === $privkey) {
195 1
            throw new \RuntimeException(
196
                'openssl_pkey_get_private() failed: ' .
197 1
                     $this->_getLastOpenSSLError());
198
        }
199 9
        $result = openssl_private_decrypt($ciphertext, $cek, $privkey,
200 9
            $this->_paddingScheme());
201 9
        if (!$result) {
202 1
            throw new \RuntimeException(
203
                'openssl_private_decrypt() failed: ' .
204 1
                     $this->_getLastOpenSSLError());
205
        }
206 8
        return $cek;
207
    }
208
209
    /**
210
     * Get last OpenSSL error message.
211
     *
212
     * @return null|string
213
     */
214 4
    protected function _getLastOpenSSLError(): ?string
215
    {
216 4
        $msg = null;
217 4
        while (false !== ($err = openssl_error_string())) {
218 4
            $msg = $err;
219
        }
220 4
        return $msg;
221
    }
222
}
223