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
Push — master ( c4f121...b9594d )
by Joni
05:22
created

RSAESKeyAlgorithm   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 205
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 93.33%

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 8
dl 0
loc 205
ccs 56
cts 60
cp 0.9333
rs 10
c 0
b 0
f 0

12 Methods

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