Passed
Pull Request — master (#46)
by
unknown
01:55
created

OpenSsl::extractKey()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 7
rs 10
cc 2
nc 2
nop 4
1
<?php
2
3
namespace Rogierw\RwAcme\Support;
4
5
use OpenSSLAsymmetricKey;
6
use Rogierw\RwAcme\Exceptions\LetsEncryptClientException;
7
8
class OpenSsl
9
{
10
    public static function generatePrivateKey(): OpenSSLAsymmetricKey
11
    {
12
        return openssl_pkey_new([
13
            'private_key_bits' => 2048,
14
            'digest_alg' => 'sha256',
15
        ]);
16
    }
17
18
    public static function openSslKeyToString(OpenSSLAsymmetricKey $key): string
19
    {
20
        if (!openssl_pkey_export($key, $output)) {
21
            throw new LetsEncryptClientException('Exporting SSL key failed.');
22
        }
23
24
        return trim($output);
25
    }
26
27
    public static function generateCsr(
28
        array $domains,
29
        OpenSSLAsymmetricKey $privateKey,
30
        bool $isAssociative = false
31
    ): string {
32
        if ($isAssociative) {
33
            $san = [];
34
35
            self::extractKey($domains, $san, 'dns', 'DNS');
36
            self::extractKey($domains, $san, 'ip', 'IP Address');
37
38
            $san = implode(',', $san);
39
40
            $dn = implode(',', array_map(function ($key, $value) {
41
                return $key . ':' . $value;
42
            }, $domains));
43
        } else {
44
            $dn = ['commonName' => $domains[0]];
45
46
            $san = implode(',', array_map(function ($dns) {
47
                return 'DNS:' . $dns;
48
            }, $domains));
49
        }
50
51
        $tempFile = tmpfile();
52
53
        fwrite(
54
            $tempFile,
55
            'HOME = .
56
			RANDFILE = $ENV::HOME/.rnd
57
			[ req ]
58
			default_bits = 4096
59
			default_keyfile = privkey.pem
60
			distinguished_name = req_distinguished_name
61
			req_extensions = v3_req
62
			[ req_distinguished_name ]
63
			countryName = Country Name (2 letter code)
64
			[ v3_req ]
65
			basicConstraints = CA:FALSE
66
			subjectAltName = ' . $san . '
67
			keyUsage = nonRepudiation, digitalSignature, keyEncipherment'
68
        );
69
70
        $csr = openssl_csr_new($dn, $privateKey, [
0 ignored issues
show
Bug introduced by
It seems like $dn can also be of type string; however, parameter $distinguished_names of openssl_csr_new() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

70
        $csr = openssl_csr_new(/** @scrutinizer ignore-type */ $dn, $privateKey, [
Loading history...
71
            'digest_alg' => 'sha256',
72
            'config' => stream_get_meta_data($tempFile)['uri'],
73
        ]);
74
75
        fclose($tempFile);
76
77
        if (!openssl_csr_export($csr, $out)) {
78
            throw new LetsEncryptClientException('Exporting CSR failed.');
79
        }
80
81
        return trim($out);
82
    }
83
84
    private static function extractKey(array &$domains, array &$san, string $key, string $name): void
85
    {
86
        if (!empty($domains[$key])) {
87
            $san = array_merge($san, array_map(function ($ip) use ($name) {
88
                return $name . ':' . $ip;
89
            }, $domains[$key]));
90
            unset($domains[$key]);
91
        }
92
    }
93
}
94