1
|
|
|
<?php |
2
|
|
|
namespace CfdiUtils\OpenSSL; |
3
|
|
|
|
4
|
|
|
use CfdiUtils\Utils\Internal\TemporaryFile; |
5
|
|
|
|
6
|
|
|
class OpenSSL |
7
|
|
|
{ |
8
|
|
|
/** @var Caller */ |
9
|
|
|
private $caller; |
10
|
|
|
|
11
|
94 |
|
public function __construct(string $opensslCommand = '') |
12
|
|
|
{ |
13
|
94 |
|
$this->caller = new Caller($opensslCommand); |
14
|
94 |
|
} |
15
|
|
|
|
16
|
2 |
|
public function getOpenSSLCommand(): string |
17
|
|
|
{ |
18
|
2 |
|
return $this->caller->getExecutable(); |
19
|
|
|
} |
20
|
|
|
|
21
|
16 |
|
public function readPemFile(string $pemFile): PemContainer |
22
|
|
|
{ |
23
|
16 |
|
$this->checkInputFile($pemFile); |
24
|
12 |
|
return $this->readPemContents(strval(file_get_contents($pemFile))); |
25
|
|
|
} |
26
|
|
|
|
27
|
75 |
|
public function readPemContents(string $contents): PemContainer |
28
|
|
|
{ |
29
|
75 |
|
$extractor = new PemExtractor($contents); |
30
|
75 |
|
$pemContainer = $extractor->pemContainer(); |
31
|
75 |
|
return $pemContainer; |
32
|
|
|
} |
33
|
|
|
|
34
|
35 |
|
public function derCerConvertPhp(string $derContent): string |
35
|
|
|
{ |
36
|
35 |
|
return '-----BEGIN CERTIFICATE-----' . PHP_EOL |
37
|
35 |
|
. chunk_split(base64_encode($derContent), 64, PHP_EOL) |
38
|
35 |
|
. '-----END CERTIFICATE-----'; |
39
|
|
|
} |
40
|
|
|
|
41
|
1 |
|
public function derCerConvert(string $derInFile, string $pemOutFile) |
42
|
|
|
{ |
43
|
1 |
|
$this->checkInputFile($derInFile); |
44
|
1 |
|
$this->checkOutputFile($pemOutFile); |
45
|
1 |
|
$this->caller->call( |
46
|
1 |
|
'x509 -inform DER -in ? -outform PEM -out ?', |
47
|
1 |
|
[$derInFile, $pemOutFile] |
48
|
|
|
); |
49
|
1 |
|
} |
50
|
|
|
|
51
|
1 |
|
public function derCerConvertOut(string $derInFile): string |
52
|
|
|
{ |
53
|
1 |
|
$pemOutFile = TemporaryFile::create(); |
54
|
1 |
|
return $pemOutFile->runAndRemove( |
55
|
|
|
function () use ($derInFile, $pemOutFile): string { |
56
|
1 |
|
$this->derCerConvert($derInFile, $pemOutFile); |
57
|
1 |
|
return rtrim($pemOutFile->retriveContents(), PHP_EOL); |
58
|
1 |
|
} |
59
|
|
|
); |
60
|
|
|
} |
61
|
|
|
|
62
|
1 |
|
public function derCerConvertInOut(string $derContents): string |
63
|
|
|
{ |
64
|
1 |
|
$derInFile = TemporaryFile::create(); |
65
|
1 |
|
return $derInFile->runAndRemove( |
66
|
|
|
function () use ($derInFile, $derContents): string { |
67
|
1 |
|
$derInFile->storeContents($derContents); |
68
|
1 |
|
return $this->derCerConvertOut($derInFile); |
69
|
1 |
|
} |
70
|
|
|
); |
71
|
|
|
} |
72
|
|
|
|
73
|
4 |
|
public function derKeyConvert(string $derInFile, string $inPassPhrase, string $pemOutFile) |
74
|
|
|
{ |
75
|
4 |
|
$this->checkInputFile($derInFile); |
76
|
4 |
|
$this->checkOutputFile($pemOutFile); |
77
|
|
|
|
78
|
4 |
|
$this->caller->call( |
79
|
4 |
|
'pkcs8 -inform DER -in ? -passin env:PASSIN -out ?', |
80
|
4 |
|
[$derInFile, $pemOutFile], |
81
|
4 |
|
['PASSIN' => $inPassPhrase] |
82
|
|
|
); |
83
|
3 |
|
} |
84
|
|
|
|
85
|
2 |
|
public function derKeyConvertOut(string $derInFile, string $inPassPhrase): string |
86
|
|
|
{ |
87
|
2 |
|
$pemOutFile = TemporaryFile::create(); |
88
|
2 |
|
return $pemOutFile->runAndRemove( |
89
|
|
|
function () use ($derInFile, $inPassPhrase, $pemOutFile): string { |
90
|
2 |
|
$this->derKeyConvert($derInFile, $inPassPhrase, $pemOutFile); |
91
|
1 |
|
return rtrim($pemOutFile->retriveContents(), PHP_EOL); |
92
|
2 |
|
} |
93
|
|
|
); |
94
|
|
|
} |
95
|
|
|
|
96
|
2 |
|
public function derKeyProtect(string $derInFile, string $inPassPhrase, string $pemOutFile, string $outPassPhrase) |
97
|
|
|
{ |
98
|
2 |
|
$tempfile = TemporaryFile::create(); |
99
|
2 |
|
$tempfile->runAndRemove( |
100
|
|
|
function () use ($derInFile, $inPassPhrase, $tempfile, $pemOutFile, $outPassPhrase) { |
101
|
2 |
|
$this->derKeyConvert($derInFile, $inPassPhrase, $tempfile); |
102
|
2 |
|
$this->pemKeyProtect($tempfile, '', $pemOutFile, $outPassPhrase); |
103
|
2 |
|
} |
104
|
|
|
); |
105
|
2 |
|
} |
106
|
|
|
|
107
|
2 |
|
public function derKeyProtectOut(string $pemInFile, string $inPassPhrase, string $outPassPhrase): string |
108
|
|
|
{ |
109
|
2 |
|
$pemOutFile = TemporaryFile::create(); |
110
|
2 |
|
return $pemOutFile->runAndRemove( |
111
|
|
|
function () use ($pemInFile, $inPassPhrase, $pemOutFile, $outPassPhrase): string { |
112
|
2 |
|
$this->derKeyProtect($pemInFile, $inPassPhrase, $pemOutFile, $outPassPhrase); |
113
|
2 |
|
return rtrim($pemOutFile->retriveContents(), PHP_EOL); |
114
|
2 |
|
} |
115
|
|
|
); |
116
|
|
|
} |
117
|
|
|
|
118
|
5 |
|
public function pemKeyProtect(string $pemInFile, string $inPassPhrase, string $pemOutFile, string $outPassPhrase) |
119
|
|
|
{ |
120
|
5 |
|
if ('' === $outPassPhrase) { |
121
|
2 |
|
$this->pemKeyUnprotect($pemInFile, $inPassPhrase, $pemOutFile); |
122
|
2 |
|
return; |
123
|
|
|
} |
124
|
|
|
|
125
|
3 |
|
$this->checkInputFile($pemInFile); |
126
|
3 |
|
$this->checkOutputFile($pemOutFile); |
127
|
|
|
|
128
|
3 |
|
$this->caller->call( |
129
|
3 |
|
'rsa -in ? -passin env:PASSIN -des3 -out ? -passout env:PASSOUT', |
130
|
3 |
|
[$pemInFile, $pemOutFile], |
131
|
3 |
|
['PASSIN' => $inPassPhrase, 'PASSOUT' => $outPassPhrase] |
132
|
|
|
); |
133
|
3 |
|
} |
134
|
|
|
|
135
|
3 |
|
public function pemKeyProtectOut(string $pemInFile, string $inPassPhrase, string $outPassPhrase): string |
136
|
|
|
{ |
137
|
3 |
|
$pemOutFile = TemporaryFile::create(); |
138
|
3 |
|
return $pemOutFile->runAndRemove( |
139
|
|
|
function () use ($pemInFile, $inPassPhrase, $pemOutFile, $outPassPhrase): string { |
140
|
3 |
|
$this->pemKeyProtect($pemInFile, $inPassPhrase, $pemOutFile, $outPassPhrase); |
141
|
3 |
|
return rtrim($pemOutFile->retriveContents(), PHP_EOL); |
142
|
3 |
|
} |
143
|
|
|
); |
144
|
|
|
} |
145
|
|
|
|
146
|
3 |
|
public function pemKeyProtectInOut(string $pemContents, string $inPassPhrase, string $outPassPhrase): string |
147
|
|
|
{ |
148
|
3 |
|
$pemInFile = TemporaryFile::create(); |
149
|
3 |
|
return $pemInFile->runAndRemove( |
150
|
|
|
function () use ($pemInFile, $pemContents, $inPassPhrase, $outPassPhrase): string { |
151
|
3 |
|
$pemInFile->storeContents($pemContents); |
152
|
3 |
|
return $this->pemKeyProtectOut($pemInFile, $inPassPhrase, $outPassPhrase); |
153
|
3 |
|
} |
154
|
|
|
); |
155
|
|
|
} |
156
|
|
|
|
157
|
3 |
|
public function pemKeyUnprotect(string $pemInFile, string $inPassPhrase, string $pemOutFile) |
158
|
|
|
{ |
159
|
3 |
|
$this->checkInputFile($pemInFile); |
160
|
3 |
|
$this->checkOutputFile($pemOutFile); |
161
|
|
|
|
162
|
3 |
|
$this->caller->call( |
163
|
3 |
|
'rsa -in ? -passin env:PASSIN -out ?', |
164
|
3 |
|
[$pemInFile, $pemOutFile], |
165
|
3 |
|
['PASSIN' => $inPassPhrase] |
166
|
|
|
); |
167
|
3 |
|
} |
168
|
|
|
|
169
|
1 |
|
public function pemKeyUnprotectOut(string $pemInFile, string $inPassPhrase): string |
170
|
|
|
{ |
171
|
1 |
|
$pemOutFile = TemporaryFile::create(); |
172
|
1 |
|
return $pemOutFile->runAndRemove( |
173
|
|
|
function () use ($pemInFile, $inPassPhrase, $pemOutFile): string { |
174
|
1 |
|
$this->pemKeyUnprotect($pemInFile, $inPassPhrase, $pemOutFile); |
175
|
1 |
|
return rtrim($pemOutFile->retriveContents(), PHP_EOL); |
176
|
1 |
|
} |
177
|
|
|
); |
178
|
|
|
} |
179
|
|
|
|
180
|
1 |
|
public function pemKeyUnprotectInOut(string $pemContents, string $inPassPhrase): string |
181
|
|
|
{ |
182
|
1 |
|
$pemInFile = TemporaryFile::create(); |
183
|
1 |
|
return $pemInFile->runAndRemove( |
184
|
|
|
function () use ($pemInFile, $pemContents, $inPassPhrase): string { |
185
|
1 |
|
$pemInFile->storeContents($pemContents); |
186
|
1 |
|
return $this->pemKeyUnprotectOut($pemInFile, $inPassPhrase); |
187
|
1 |
|
} |
188
|
|
|
); |
189
|
|
|
} |
190
|
|
|
|
191
|
28 |
|
protected function checkInputFile(string $path) |
192
|
|
|
{ |
193
|
|
|
// file must exists, not a directory and must contain a non-zero size |
194
|
28 |
|
if ('' === $path) { |
195
|
2 |
|
throw new OpenSSLException('File argument is empty'); |
196
|
|
|
} |
197
|
26 |
|
if (! file_exists($path)) { |
198
|
3 |
|
throw new OpenSSLException("File $path does not exists"); |
199
|
|
|
} |
200
|
23 |
|
if (is_dir($path)) { |
201
|
2 |
|
throw new OpenSSLException("File $path is a directory"); |
202
|
|
|
} |
203
|
21 |
|
if (filesize($path) === 0) { |
204
|
1 |
|
throw new OpenSSLException("File $path is empty"); |
205
|
|
|
} |
206
|
20 |
|
} |
207
|
|
|
|
208
|
15 |
|
protected function checkOutputFile(string $path) |
209
|
|
|
{ |
210
|
|
|
// file should not exists or exists but contain a zero size |
211
|
15 |
|
if ('' === $path) { |
212
|
1 |
|
throw new OpenSSLException('File argument is empty'); |
213
|
|
|
} |
214
|
14 |
|
if (! file_exists($path)) { |
215
|
2 |
|
if (! is_dir(dirname($path))) { |
216
|
1 |
|
throw new OpenSSLException("Directory of $path does not exists"); |
217
|
|
|
} |
218
|
1 |
|
return; |
219
|
|
|
} |
220
|
12 |
|
if (is_dir($path)) { |
221
|
1 |
|
throw new OpenSSLException("File $path is a directory"); |
222
|
|
|
} |
223
|
11 |
|
if (filesize($path) > 0) { |
224
|
1 |
|
throw new OpenSSLException("File $path is not empty"); |
225
|
|
|
} |
226
|
10 |
|
} |
227
|
|
|
} |
228
|
|
|
|