Passed
Push — master ( 5b9510...250720 )
by Daniel
01:40
created

PrivateKeyStore::getPrivateKeyAsPem()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Selective\XmlDSig;
4
5
use OpenSSLAsymmetricKey;
6
use OpenSSLCertificate;
7
use Selective\XmlDSig\Exception\CertificateException;
8
use Selective\XmlDSig\Exception\XmlSignerException;
9
use UnexpectedValueException;
10
11
final class PrivateKeyStore
12
{
13
    /**
14
     * @var OpenSSLCertificate[]
15
     */
16
    private array $certificates = [];
17
18
    private ?OpenSSLAsymmetricKey $privateKey = null;
19
20
    private ?string $privateKeyPem = null;
21
22
    private ?string $modulus = null;
23
24
    private ?string $publicExponent = null;
25
26
    /**
27
     * Add X509 certificate.
28
     *
29
     * @param OpenSSLCertificate $certificate
30
     *
31
     * @return void
32
     */
33
    public function addCertificate(OpenSSLCertificate $certificate): void
34
    {
35
        $this->certificates[] = $certificate;
36
    }
37
38
    /**
39
     * Get X509 certificates.
40
     *
41
     * @return OpenSSLCertificate[]
42
     */
43 3
    public function getCertificates(): array
44
    {
45 3
        return $this->certificates;
46
    }
47
48
    /**
49
     * Load X509 certificates from PEM.
50
     * PEM is a base64 format for certificates.
51
     *
52
     * @param string $certificate The certificate bundle
53
     *
54
     * @return void
55
     */
56
    public function addCertificatesFromX509Pem(string $certificate): void
57
    {
58
        $x509Reader = new X509Reader();
59
        foreach ($x509Reader->fromPem($certificate) as $certificate) {
60
            $this->addCertificate($certificate);
61
        }
62
    }
63
64
    /**
65
     * Read and load a private key.
66
     *
67
     * @param string $pem The PEM formatted private key
68
     * @param string $password The PEM password
69
     *
70
     * @throws XmlSignerException
71
     *
72
     * @return void
73
     */
74 2
    public function loadFromPem(string $pem, string $password): void
75
    {
76
        // Read the private key
77 2
        $privateKey = openssl_pkey_get_private($pem, $password);
78
79 2
        if (!$privateKey) {
80
            throw new XmlSignerException('Invalid password or private key');
81
        }
82
83 2
        $this->privateKey = $privateKey;
84 2
        $this->privateKeyPem = $pem;
85
86 2
        $this->loadPrivateKeyDetails();
87
    }
88
89
    /**
90
     * Load the PKCS12 (PFX) content.
91
     *
92
     * PKCS12 is an encrypted container that contains the
93
     * public key and private key combined in binary format.
94
     *
95
     * @param string $pkcs12 The content
96
     * @param string $password The password
97
     *
98
     * @throws CertificateException
99
     *
100
     * @return void
101
     */
102 1
    public function loadFromPkcs12(string $pkcs12, string $password): void
103
    {
104 1
        $status = openssl_pkcs12_read($pkcs12, $certInfo, $password);
105
106 1
        if (!$status) {
107
            throw new CertificateException('Invalid certificate password');
108
        }
109
110
        // Read the private key
111 1
        $this->privateKeyPem = (string)$certInfo['pkey'];
112
113 1
        if (!$this->privateKeyPem) {
114
            throw new CertificateException('Invalid or missing private key');
115
        }
116
117 1
        $privateKey = openssl_pkey_get_private($this->privateKeyPem);
118
119 1
        if (!$privateKey) {
120
            throw new CertificateException('Invalid private key');
121
        }
122
123 1
        $this->privateKey = $privateKey;
124
125 1
        $this->loadPrivateKeyDetails();
126
    }
127
128
    /**
129
     * Load private key details.
130
     *
131
     * @throws UnexpectedValueException
132
     *
133
     * @return void
134
     */
135 3
    private function loadPrivateKeyDetails(): void
136
    {
137 3
        if (!$this->privateKey) {
138
            throw new UnexpectedValueException('Private key is not defined');
139
        }
140
141 3
        $details = openssl_pkey_get_details($this->privateKey);
142
143 3
        if ($details === false) {
144
            throw new UnexpectedValueException('Invalid private key');
145
        }
146
147 3
        $key = $this->getPrivateKeyDetailKey($details['type']);
148
149 3
        if (isset($details[$key]['n'])) {
150 2
            $this->modulus = base64_encode($details[$key]['n']);
151
        }
152 3
        if (isset($details[$key]['e'])) {
153 2
            $this->publicExponent = base64_encode($details[$key]['e']);
154
        }
155
    }
156
157
    /**
158
     * Get private key details key type.
159
     *
160
     * @param int $type The type
161
     *
162
     * @return string The array key
163
     */
164 3
    private function getPrivateKeyDetailKey(int $type): string
165
    {
166 3
        $key = '';
167 3
        $key = $type === OPENSSL_KEYTYPE_RSA ? 'rsa' : $key;
168 3
        $key = $type === OPENSSL_KEYTYPE_DSA ? 'dsa' : $key;
169 3
        $key = $type === OPENSSL_KEYTYPE_DH ? 'dh' : $key;
170 3
        $key = $type === OPENSSL_KEYTYPE_EC ? 'ec' : $key;
171
172 3
        return $key;
173
    }
174
175 2
    public function getPrivateKey(): ?OpenSSLAsymmetricKey
176
    {
177 2
        return $this->privateKey;
178
    }
179
180 1
    public function getPrivateKeyAsPem(): ?string
181
    {
182 1
        return $this->privateKeyPem;
183
    }
184
185 3
    public function getModulus(): ?string
186
    {
187 3
        return $this->modulus;
188
    }
189
190 3
    public function getPublicExponent(): ?string
191
    {
192 3
        return $this->publicExponent;
193
    }
194
}
195