@@ -64,9 +64,7 @@ private function importPfx(string $pfxContent, string $password, string $cnpj):
6464 $ lastError = openssl_error_string () ?: '' ;
6565
6666 if (str_contains ($ lastError , self ::LEGACY_OPENSSL_ERROR )) {
67- // Legacy PFX — re-pack via CLI and retry
68- $ pfxContent = $ this ->repackLegacyPfx ($ pfxContent , $ password );
69- $ ok = openssl_pkcs12_read ($ pfxContent , $ certs , $ password );
67+ return $ this ->extractLegacyPemMaterial ($ pfxContent , $ password , $ cnpj );
7068 }
7169
7270 if (!$ ok ) {
@@ -82,10 +80,12 @@ private function importPfx(string $pfxContent, string $password, string $cnpj):
8280 }
8381
8482 /**
85- * Re-pack a legacy PFX into a modern one using the OpenSSL CLI.
83+ * Extract private key and leaf certificate from a legacy PFX via OpenSSL CLI.
8684 * The password is passed via environment variable to avoid shell injection.
85+ *
86+ * @return array{string, string} [privateKeyPem, certificatePem]
8787 */
88- private function repackLegacyPfx (string $ pfxContent , string $ password ): string
88+ private function extractLegacyPemMaterial (string $ pfxContent , string $ password, string $ cnpj ): array
8989 {
9090 $ tmpIn = tempnam (sys_get_temp_dir (), 'nfse_in_ ' );
9191 $ tmpOut = tempnam (sys_get_temp_dir (), 'nfse_out_ ' );
@@ -100,7 +100,7 @@ private function repackLegacyPfx(string $pfxContent, string $password): string
100100 // Use env var to avoid password in process list (avoids shell injection)
101101 putenv ('NFSE_PFX_PASS= ' . $ password );
102102 $ cmd = sprintf (
103- 'openssl pkcs12 -legacy -in %s -passin env:NFSE_PFX_PASS -out %s -passout env:NFSE_PFX_PASS 2>/dev/null ' ,
103+ 'openssl pkcs12 -legacy -in %s -passin env:NFSE_PFX_PASS -nodes - out %s 2>/dev/null ' ,
104104 escapeshellarg ($ tmpIn ),
105105 escapeshellarg ($ tmpOut ),
106106 );
@@ -117,7 +117,7 @@ private function repackLegacyPfx(string $pfxContent, string $password): string
117117 throw new PfxImportException ('openssl CLI repack produced empty output ' );
118118 }
119119
120- return $ result ;
120+ return $ this -> extractPemParts ( $ result, $ cnpj ) ;
121121 } finally {
122122 putenv ('NFSE_PFX_PASS ' );
123123
@@ -130,6 +130,30 @@ private function repackLegacyPfx(string $pfxContent, string $password): string
130130 }
131131 }
132132
133+ /**
134+ * @return array{string, string} [privateKeyPem, certificatePem]
135+ */
136+ private function extractPemParts (string $ pemBundle , string $ cnpj ): array
137+ {
138+ $ privateKeyMatched = preg_match (
139+ '/-----BEGIN(?: ENCRYPTED)? PRIVATE KEY-----.*?-----END(?: ENCRYPTED)? PRIVATE KEY-----/s ' ,
140+ $ pemBundle ,
141+ $ privateKeyMatches ,
142+ ) === 1 ;
143+
144+ $ certificateMatched = preg_match (
145+ '/-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----/s ' ,
146+ $ pemBundle ,
147+ $ certificateMatches ,
148+ ) === 1 ;
149+
150+ if (!$ privateKeyMatched || !$ certificateMatched ) {
151+ throw new PfxImportException ('Failed to extract PEM material from legacy PFX for CNPJ ' . $ cnpj );
152+ }
153+
154+ return [$ privateKeyMatches [0 ], $ certificateMatches [0 ]];
155+ }
156+
133157 /**
134158 * Signs an XML document per ABRASF 2.04 / XML-DSig (RSA-SHA1, enveloped signature).
135159 *
0 commit comments