Skip to content

Commit cb5c4b3

Browse files
committed
fix: works with unicode password
JSignPdf don't works as well at CLI interfaceif the password have unicode chars. As workaround, I changed the password certificate in memory. Signed-off-by: Vitor Mattos <vitor@php.rio>
1 parent c80de15 commit cb5c4b3

2 files changed

Lines changed: 54 additions & 22 deletions

File tree

src/Sign/JSignService.php

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public function sign(JSignParam $params)
2222
{
2323
try {
2424
$this->validation($params);
25+
$this->repackCertificateIfPasswordIsUnicode($params);
2526

2627
$commandSign = $this->commandSign($params);
2728
\exec($commandSign, $output);
@@ -51,6 +52,22 @@ public function sign(JSignParam $params)
5152
}
5253
}
5354

55+
/**
56+
* JSignPdf don't works as well at CLI interfaceif the password have
57+
* unicode chars. As workaround, I changed the password certificate in
58+
* memory.
59+
*/
60+
private function repackCertificateIfPasswordIsUnicode(JSignParam $params)
61+
{
62+
if (!mb_detect_encoding($params->getPassword(), 'ASCII', true)) {
63+
$password = md5(microtime());
64+
$certInfo = $this->pkcs12Read($params);
65+
$newCert = $this->exportToPkcs12($certInfo['cert'], $certInfo['pkey'], $password);
66+
$params->setPassword($password);
67+
$params->setCertificate($newCert);
68+
}
69+
}
70+
5471
public function getVersion(JSignParam $params)
5572
{
5673
$java = $this->javaCommand($params);
@@ -75,8 +92,8 @@ private function validation(JSignParam $params)
7592
$this->throwIf(empty($params->getPdf()), 'PDF is Empty or Invalid.');
7693
$this->throwIf(empty($params->getCertificate()), 'Certificate is Empty or Invalid.');
7794
$this->throwIf(empty($params->getPassword()), 'Certificate Password is Empty.');
78-
$this->throwIf(!$this->isPasswordCertificateValid($params->getCertificate(), $params->getPassword()), 'Certificate Password Invalid.');
79-
$this->throwIf($this->isExpiredCertificate($params->getCertificate(), $params->getPassword()), 'Certificate expired.');
95+
$this->throwIf(!$this->isPasswordCertificateValid($params), 'Certificate Password Invalid.');
96+
$this->throwIf($this->isExpiredCertificate($params), 'Certificate expired.');
8097
if ($params->isUseJavaInstalled()) {
8198
$javaVersion = exec("java -version 2>&1");
8299
$hasJavaVersion = strpos($javaVersion, 'not found') === false;
@@ -135,9 +152,9 @@ private function throwIf($condition, $message)
135152
throw new Exception($message);
136153
}
137154

138-
private function isPasswordCertificateValid($certificate, $password)
155+
private function isPasswordCertificateValid(JSignParam $params)
139156
{
140-
return $this->pkcs12Read($certificate, $password);
157+
return $this->pkcs12Read($params);
141158
}
142159

143160
/**
@@ -153,8 +170,10 @@ private function isPasswordCertificateValid($certificate, $password)
153170
* https://github.com/php/php-src/issues/12128
154171
* https://www.php.net/manual/en/function.openssl-pkcs12-read.php#128992
155172
*/
156-
private function pkcs12Read($certificate, $password)
173+
private function pkcs12Read(JSignParam $params)
157174
{
175+
$certificate = $params->getCertificate();
176+
$password = $params->getPassword();
158177
if (openssl_pkcs12_read($certificate, $certInfo, $password)) {
159178
return $certInfo;
160179
}
@@ -175,6 +194,7 @@ private function pkcs12Read($certificate, $password)
175194
REPACK_COMMAND
176195
);
177196
$certificateRepacked = file_get_contents($tempEncriptedRepacked);
197+
$params->setCertificate($certificateRepacked);
178198
unlink($tempPassword);
179199
unlink($tempEncriptedOriginal);
180200
unlink($tempEncriptedRepacked);
@@ -185,9 +205,21 @@ private function pkcs12Read($certificate, $password)
185205
return [];
186206
}
187207

188-
private function isExpiredCertificate($certificate, $password)
208+
public function exportToPkcs12(\OpenSSLCertificate|string $certificate, \OpenSSLAsymmetricKey|\OpenSSLCertificate|string $privateKey, string $password)
209+
{
210+
$certContent = null;
211+
openssl_pkcs12_export(
212+
$certificate,
213+
$certContent,
214+
$privateKey,
215+
$password,
216+
);
217+
return $certContent;
218+
}
219+
220+
private function isExpiredCertificate(JSignParam $params)
189221
{
190-
$certInfo = $this->pkcs12Read($certificate, $password);
222+
$certInfo = $this->pkcs12Read($params);
191223
$certificate = openssl_x509_parse($certInfo['cert']);
192224
$dateCert = date_create()->setTimestamp($certificate['validTo_time_t']);
193225
return $dateCert <= date_create();

tests/JSignPDFTest.php

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,7 @@ private function getNewCert($password)
4141
$temporaryFile = tempnam(sys_get_temp_dir(), 'cfg');
4242
$csr = openssl_csr_new($csrNames, $privateKey);
4343
$x509 = openssl_csr_sign($csr, $rootCertificate, $rootPrivateKey, 365);
44-
return $this->exportToPkcs12($x509, $privateKey, $password);
45-
}
46-
47-
private function exportToPkcs12(\OpenSSLCertificate $certificate, \OpenSSLAsymmetricKey $privateKey, string $password)
48-
{
49-
$certContent = null;
50-
openssl_pkcs12_export(
51-
$certificate,
52-
$certContent,
53-
$privateKey,
54-
$password,
55-
);
56-
return $certContent;
44+
return $this->service->exportToPkcs12($x509, $privateKey, $password);
5745
}
5846

5947
public function testSignSuccess()
@@ -67,19 +55,31 @@ public function testSignSuccess()
6755
$this->assertNotNull($fileSigned);
6856
}
6957

70-
public function testSignUsingPasswordWithQuote()
58+
/**
59+
* @dataProvider providerSignUsingDifferentPasswords
60+
*/
61+
public function testSignUsingDifferentPasswords(string $password)
7162
{
7263
if (!class_exists('JSignPDF\JSignPDFBin\JavaCommandService')) {
7364
$this->markTestSkipped('Install jsignpdf/jsignpdf-bin');
7465
}
7566
$params = JSignParamBuilder::instance()->withDefault();
76-
$password = "with ' quote";
7767
$params->setCertificate($this->getNewCert($password));
7868
$params->setPassword($password);
7969
$fileSigned = $this->service->sign($params);
8070
$this->assertNotNull($fileSigned);
8171
}
8272

73+
public function providerSignUsingDifferentPasswords()
74+
{
75+
return [
76+
["with ' quote"],
77+
['with ( parentheis )'],
78+
['with $ dollar'],
79+
['with 😃 unicode'],
80+
];
81+
}
82+
8383
public function testCertificateExpired()
8484
{
8585
if (!class_exists('JSignPDF\JSignPDFBin\JavaCommandService')) {

0 commit comments

Comments
 (0)