Failed Conditions
Push — master ( df44e5...b25e13 )
by Florent
02:17
created

JWKFactory::createFromSecret()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2018 Spomky-Labs
9
 *
10
 * This software may be modified and distributed under the terms
11
 * of the MIT license.  See the LICENSE file for details.
12
 */
13
14
namespace Jose\Component\KeyManagement;
15
16
use Base64Url\Base64Url;
17
use Jose\Component\Core\JWK;
18
use Jose\Component\Core\JWKSet;
19
use Jose\Component\Core\Util\Ecc\NistCurve;
20
use Jose\Component\KeyManagement\KeyConverter\KeyConverter;
21
use Jose\Component\KeyManagement\KeyConverter\RSAKey;
22
23
/**
24
 * Class JWKFactory.
25
 */
26
final class JWKFactory
27
{
28
    /**
29
     * @param int   $size   The key size in bits
30
     * @param array $values values to configure the key
31
     *
32
     * @return JWK
33
     */
34
    public static function createRSAKey(int $size, array $values = []): JWK
35
    {
36
        if (0 !== $size % 8) {
37
            throw new \InvalidArgumentException('Invalid key size.');
38
        }
39
40
        if (384 > $size) {
41
            throw new \InvalidArgumentException('Key length is too short. It needs to be at least 384 bits.');
42
        }
43
44
        $key = openssl_pkey_new([
45
            'private_key_bits' => $size,
46
            'private_key_type' => OPENSSL_KEYTYPE_RSA,
47
        ]);
48
        openssl_pkey_export($key, $out);
49
        $rsa = RSAKey::createFromPEM($out);
50
        $values = array_merge(
51
            $values,
52
            $rsa->toArray()
53
        );
54
55
        return JWK::create($values);
56
    }
57
58
    /**
59
     * @param string $curve  The curve
60
     * @param array  $values values to configure the key
61
     *
62
     * @return JWK
63
     */
64
    public static function createECKey(string $curve, array $values = []): JWK
65
    {
66
        switch ($curve) {
67
            case 'P-256':
68
                $nistCurve = NistCurve::curve256();
69
70
                break;
71
            case 'P-384':
72
                $nistCurve = NistCurve::curve384();
73
74
                break;
75
            case 'P-521':
76
                $nistCurve = NistCurve::curve521();
77
78
                break;
79
            default:
80
                throw new \InvalidArgumentException(sprintf('The curve "%s" is not supported.', $curve));
81
        }
82
83
        $privateKey = $nistCurve->createPrivateKey();
84
        $publicKey = $nistCurve->createPublicKey($privateKey);
85
86
        $values = array_merge(
87
            $values,
88
            [
89
                'kty' => 'EC',
90
                'crv' => $curve,
91
                'd' => Base64Url::encode(gmp_export($privateKey->getSecret())),
92
                'x' => Base64Url::encode(gmp_export($publicKey->getPoint()->getX())),
93
                'y' => Base64Url::encode(gmp_export($publicKey->getPoint()->getY())),
94
            ]
95
        );
96
97
        return JWK::create($values);
98
    }
99
100
    /**
101
     * @param int   $size   The key size in bits
102
     * @param array $values values to configure the key
103
     *
104
     * @return JWK
105
     */
106
    public static function createOctKey(int $size, array $values = []): JWK
107
    {
108
        if (0 !== $size % 8) {
109
            throw new \InvalidArgumentException('Invalid key size.');
110
        }
111
        $values = array_merge(
112
            $values,
113
            [
114
                'kty' => 'oct',
115
                'k' => Base64Url::encode(random_bytes($size / 8)),
116
            ]
117
        );
118
119
        return JWK::create($values);
120
    }
121
122
    /**
123
     * @param string $curve  The curve
124
     * @param array  $values values to configure the key
125
     *
126
     * @return JWK
127
     */
128
    public static function createOKPKey(string $curve, array $values = []): JWK
129
    {
130
        switch ($curve) {
131
            case 'X25519':
132
                $keyPair = sodium_crypto_box_keypair();
133
                $d = sodium_crypto_box_secretkey($keyPair);
134
                $x = sodium_crypto_box_publickey($keyPair);
135
136
                break;
137
            case 'Ed25519':
138
                $keyPair = sodium_crypto_sign_keypair();
139
                $d = sodium_crypto_sign_secretkey($keyPair);
140
                $x = sodium_crypto_sign_publickey($keyPair);
141
142
                break;
143
            default:
144
                throw new \InvalidArgumentException(sprintf('Unsupported "%s" curve', $curve));
145
        }
146
147
        $values = array_merge(
148
            $values,
149
            [
150
                'kty' => 'OKP',
151
                'crv' => $curve,
152
                'x' => Base64Url::encode($x),
153
                'd' => Base64Url::encode($d),
154
            ]
155
        );
156
157
        return JWK::create($values);
158
    }
159
160
    /**
161
     * @param array $values values to configure the key
162
     *
163
     * @return JWK
164
     */
165
    public static function createNoneKey(array $values = []): JWK
166
    {
167
        $values = array_merge(
168
            $values,
169
            [
170
                'kty' => 'none',
171
                'alg' => 'none',
172
                'use' => 'sig',
173
            ]
174
        );
175
176
        return JWK::create($values);
177
    }
178
179
    /**
180
     * @param string $value
181
     *
182
     * @return JWK|JWKSet
183
     */
184
    public static function createFromJsonObject(string $value)
185
    {
186
        $json = json_decode($value, true);
187
        if (!is_array($json)) {
188
            throw new \InvalidArgumentException('Invalid key or key set.');
189
        }
190
191
        return self::createFromValues($json);
192
    }
193
194
    /**
195
     * @param array $values
196
     *
197
     * @return JWK|JWKSet
198
     */
199
    public static function createFromValues(array $values)
200
    {
201
        if (array_key_exists('keys', $values) && is_array($values['keys'])) {
202
            return JWKSet::createFromKeyData($values);
203
        }
204
205
        return JWK::create($values);
206
    }
207
208
    /**
209
     * This method create a JWK object using a shared secret.
210
     *
211
     * @param string $secret
212
     * @param array  $additional_values
213
     *
214
     * @return JWK
215
     */
216
    public static function createFromSecret(string $secret, array $additional_values = []): JWK
217
    {
218
        $values = array_merge(
219
            $additional_values,
220
            [
221
                'kty' => 'oct',
222
                'k' => Base64Url::encode($secret),
223
            ]
224
        );
225
226
        return JWK::create($values);
227
    }
228
229
    /**
230
     * @param string $file
231
     * @param array  $additional_values
232
     *
233
     * @return JWK
234
     */
235
    public static function createFromCertificateFile(string $file, array $additional_values = []): JWK
236
    {
237
        $values = KeyConverter::loadKeyFromCertificateFile($file);
238
        $values = array_merge($values, $additional_values);
239
240
        return JWK::create($values);
241
    }
242
243
    /**
244
     * @param JWKSet     $jwkset
245
     * @param int|string $index
246
     *
247
     * @return JWK
248
     */
249
    public static function createFromKeySet(JWKSet $jwkset, $index): JWK
250
    {
251
        return $jwkset->get($index);
252
    }
253
254
    /**
255
     * @param string      $file
256
     * @param null|string $secret
257
     * @param array       $additional_values
258
     *
259
     * @throws \Exception
260
     *
261
     * @return JWK
262
     */
263
    public static function createFromPKCS12CertificateFile(string $file, ?string $secret = '', array $additional_values = []): JWK
264
    {
265
        $res = openssl_pkcs12_read(file_get_contents($file), $certs, $secret);
266
        if (false === $res || !is_array($certs) || !array_key_exists('pkey', $certs)) {
267
            throw new \RuntimeException('Unable to load the certificates.');
268
        }
269
270
        return self::createFromKey($certs['pkey'], null, $additional_values);
271
    }
272
273
    /**
274
     * @param string $certificate
275
     * @param array  $additional_values
276
     *
277
     * @return JWK
278
     */
279
    public static function createFromCertificate(string $certificate, array $additional_values = []): JWK
280
    {
281
        $values = KeyConverter::loadKeyFromCertificate($certificate);
282
        $values = array_merge($values, $additional_values);
283
284
        return JWK::create($values);
285
    }
286
287
    /**
288
     * @param resource $res
289
     * @param array    $additional_values
290
     *
291
     * @throws \Exception
292
     *
293
     * @return JWK
294
     */
295
    public static function createFromX509Resource($res, array $additional_values = []): JWK
296
    {
297
        $values = KeyConverter::loadKeyFromX509Resource($res);
298
        $values = array_merge($values, $additional_values);
299
300
        return JWK::create($values);
301
    }
302
303
    /**
304
     * @param string      $file
305
     * @param null|string $password
306
     * @param array       $additional_values
307
     *
308
     * @throws \Exception
309
     *
310
     * @return JWK
311
     */
312
    public static function createFromKeyFile(string $file, ?string $password = null, array $additional_values = []): JWK
313
    {
314
        $values = KeyConverter::loadFromKeyFile($file, $password);
315
        $values = array_merge($values, $additional_values);
316
317
        return JWK::create($values);
318
    }
319
320
    /**
321
     * @param string      $key
322
     * @param null|string $password
323
     * @param array       $additional_values
324
     *
325
     * @throws \Exception
326
     *
327
     * @return JWK
328
     */
329
    public static function createFromKey(string $key, ?string $password = null, array $additional_values = []): JWK
330
    {
331
        $values = KeyConverter::loadFromKey($key, $password);
332
        $values = array_merge($values, $additional_values);
333
334
        return JWK::create($values);
335
    }
336
337
    /**
338
     * @param array $x5c
339
     * @param array $additional_values
340
     *
341
     * @return JWK
342
     */
343
    public static function createFromX5C(array $x5c, array $additional_values = []): JWK
344
    {
345
        $values = KeyConverter::loadFromX5C($x5c);
346
        $values = array_merge($values, $additional_values);
347
348
        return JWK::create($values);
349
    }
350
}
351