Failed Conditions
Push — master ( 1edcb4...1e22a0 )
by Florent
02:06
created

JWKFactory::createFromCertificateFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2017 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
                break;
70
            case 'P-384':
71
                $nistCurve = NistCurve::curve384();
72
                break;
73
            case 'P-521':
74
                $nistCurve = NistCurve::curve521();
75
                break;
76
            default:
77
                throw new \InvalidArgumentException(sprintf('The curve "%s" is not supported.', $curve));
78
        }
79
80
        $privateKey = $nistCurve->createPrivateKey();
81
        $publicKey = $nistCurve->createPublicKey($privateKey);
82
83
        $values = array_merge(
84
            $values,
85
            [
86
                'kty' => 'EC',
87
                'crv' => $curve,
88
                'd' => Base64Url::encode(gmp_export($privateKey->getSecret())),
89
                'x' => Base64Url::encode(gmp_export($publicKey->getPoint()->getX())),
90
                'y' => Base64Url::encode(gmp_export($publicKey->getPoint()->getY())),
91
            ]
92
        );
93
94
        return JWK::create($values);
95
    }
96
97
    /**
98
     * @param int   $size   The key size in bits
99
     * @param array $values values to configure the key
100
     *
101
     * @return JWK
102
     */
103
    public static function createOctKey(int $size, array $values = []): JWK
104
    {
105
        if (0 !== $size % 8) {
106
            throw new \InvalidArgumentException('Invalid key size.');
107
        }
108
        $values = array_merge(
109
            $values,
110
            [
111
                'kty' => 'oct',
112
                'k' => Base64Url::encode(random_bytes($size / 8)),
113
            ]
114
        );
115
116
        return JWK::create($values);
117
    }
118
119
    /**
120
     * @param string $curve  The curve
121
     * @param array  $values values to configure the key
122
     *
123
     * @return JWK
124
     */
125
    public static function createOKPKey(string $curve, array $values = []): JWK
126
    {
127
        switch ($curve) {
128
            case 'X25519':
129
                $d = sodium_randombytes_buf(\Sodium\CRYPTO_BOX_SEEDBYTES);
130
                $x = sodium_crypto_scalarmult_base($d);
131
132
                break;
133
            case 'Ed25519':
134
                $d = sodium_randombytes_buf(\Sodium\CRYPTO_SIGN_SEEDBYTES);
135
                $keyPair = sodium_crypto_sign_seed_keypair($d);
136
                $x = sodium_crypto_sign_publickey($keyPair);
137
138
                break;
139
            default:
140
                throw new \InvalidArgumentException(sprintf('Unsupported "%s" curve', $curve));
141
        }
142
143
        $values = array_merge(
144
            $values,
145
            [
146
                'kty' => 'OKP',
147
                'crv' => $curve,
148
                'x' => Base64Url::encode($x),
149
                'd' => Base64Url::encode($d),
150
            ]
151
        );
152
153
        return JWK::create($values);
154
    }
155
156
    /**
157
     * @param array $values values to configure the key
158
     *
159
     * @return JWK
160
     */
161
    public static function createNoneKey(array $values = []): JWK
162
    {
163
        $values = array_merge(
164
            $values,
165
            [
166
                'kty' => 'none',
167
                'alg' => 'none',
168
                'use' => 'sig',
169
            ]
170
        );
171
172
        return JWK::create($values);
173
    }
174
175
    /**
176
     * @param string $value
177
     *
178
     * @return JWK|JWKSet
179
     */
180
    public static function createFromString(string $value)
181
    {
182
        $json = json_decode($value, true);
183
        if (!is_array($json)) {
184
            throw new \InvalidArgumentException('Invalid key or key set.');
185
        }
186
187
        return self::createFromValues($json);
188
    }
189
190
    /**
191
     * @param array $values
192
     *
193
     * @return JWK|JWKSet
194
     */
195
    public static function createFromValues(array $values)
196
    {
197
        if (array_key_exists('keys', $values) && is_array($values['keys'])) {
198
            return JWKSet::createFromKeyData($values);
199
        }
200
201
        return JWK::create($values);
202
    }
203
204
    /**
205
     * @param string $file
206
     * @param array  $additional_values
207
     *
208
     * @return JWK
209
     */
210
    public static function createFromCertificateFile(string $file, array $additional_values = []): JWK
211
    {
212
        $values = KeyConverter::loadKeyFromCertificateFile($file);
213
        $values = array_merge($values, $additional_values);
214
215
        return JWK::create($values);
216
    }
217
218
    /**
219
     * @param string      $file
220
     * @param null|string $secret
221
     * @param array       $additional_values
222
     *
223
     * @return JWK
224
     */
225
    public static function createFromPKCS12CertificateFile(string $file, ?string $secret = null, array $additional_values = []): JWK
226
    {
227
        $res = openssl_pkcs12_read(file_get_contents($file), $certs, $secret);
228
        if (false === $res || !is_array($certs) || !array_key_exists('pkey', $certs)) {
229
            throw new \RuntimeException('Unable to load the certificates.');
230
        }
231
232
        return self::createFromKey($certs['pkey'], null, $additional_values);
233
    }
234
235
    /**
236
     * @param string $certificate
237
     * @param array  $additional_values
238
     *
239
     * @return JWK
240
     */
241
    public static function createFromCertificate(string $certificate, array $additional_values = []): JWK
242
    {
243
        $values = KeyConverter::loadKeyFromCertificate($certificate);
244
        $values = array_merge($values, $additional_values);
245
246
        return JWK::create($values);
247
    }
248
249
    /**
250
     * @param resource $res
251
     * @param array    $additional_values
252
     *
253
     * @return JWK
254
     */
255
    public static function createFromX509Resource($res, array $additional_values = []): JWK
256
    {
257
        $values = KeyConverter::loadKeyFromX509Resource($res);
258
        $values = array_merge($values, $additional_values);
259
260
        return JWK::create($values);
261
    }
262
263
    /**
264
     * @param string      $file
265
     * @param null|string $password
266
     * @param array       $additional_values
267
     *
268
     * @return JWK
269
     */
270
    public static function createFromKeyFile(string $file, ?string $password = null, array $additional_values = []): JWK
271
    {
272
        $values = KeyConverter::loadFromKeyFile($file, $password);
273
        $values = array_merge($values, $additional_values);
274
275
        return JWK::create($values);
276
    }
277
278
    /**
279
     * @param string      $key
280
     * @param null|string $password
281
     * @param array       $additional_values
282
     *
283
     * @return JWK
284
     */
285
    public static function createFromKey(string $key, ?string $password = null, array $additional_values = []): JWK
286
    {
287
        $values = KeyConverter::loadFromKey($key, $password);
288
        $values = array_merge($values, $additional_values);
289
290
        return JWK::create($values);
291
    }
292
293
    /**
294
     * @param array $x5c
295
     * @param array $additional_values
296
     *
297
     * @return JWK
298
     */
299
    public static function createFromX5C(array $x5c, array $additional_values = []): JWK
300
    {
301
        $values = KeyConverter::loadFromX5C($x5c);
302
        $values = array_merge($values, $additional_values);
303
304
        return JWK::create($values);
305
    }
306
}
307