@@ -64,28 +64,26 @@ 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
72- if (!$ ok ) {
73- $ opensslError = openssl_error_string ();
70+ $ opensslError = openssl_error_string ();
7471
75- throw new PfxImportException (
76- 'Failed to import PFX for CNPJ ' . $ cnpj . ': ' . ($ opensslError ?: 'unknown OpenSSL error ' )
77- );
78- }
72+ throw new PfxImportException (
73+ 'Failed to import PFX for CNPJ ' . $ cnpj . ': ' . ($ opensslError ?: 'unknown OpenSSL error ' )
74+ );
7975 }
8076
8177 return [$ certs ['pkey ' ], $ certs ['cert ' ]];
8278 }
8379
8480 /**
85- * Re-pack a legacy PFX into a modern one using the OpenSSL CLI.
81+ * Extract private key and leaf certificate from a legacy PFX via OpenSSL CLI.
8682 * The password is passed via environment variable to avoid shell injection.
83+ *
84+ * @return array{string, string} [privateKeyPem, certificatePem]
8785 */
88- private function repackLegacyPfx (string $ pfxContent , string $ password ): string
86+ private function extractLegacyPemMaterial (string $ pfxContent , string $ password, string $ cnpj ): array
8987 {
9088 $ tmpIn = tempnam (sys_get_temp_dir (), 'nfse_in_ ' );
9189 $ tmpOut = tempnam (sys_get_temp_dir (), 'nfse_out_ ' );
@@ -100,7 +98,7 @@ private function repackLegacyPfx(string $pfxContent, string $password): string
10098 // Use env var to avoid password in process list (avoids shell injection)
10199 putenv ('NFSE_PFX_PASS= ' . $ password );
102100 $ cmd = sprintf (
103- 'openssl pkcs12 -legacy -in %s -passin env:NFSE_PFX_PASS -out %s -passout env:NFSE_PFX_PASS 2>/dev/null ' ,
101+ 'openssl pkcs12 -legacy -in %s -passin env:NFSE_PFX_PASS -nodes - out %s 2>/dev/null ' ,
104102 escapeshellarg ($ tmpIn ),
105103 escapeshellarg ($ tmpOut ),
106104 );
@@ -117,7 +115,7 @@ private function repackLegacyPfx(string $pfxContent, string $password): string
117115 throw new PfxImportException ('openssl CLI repack produced empty output ' );
118116 }
119117
120- return $ result ;
118+ return $ this -> extractPemParts ( $ result, $ cnpj ) ;
121119 } finally {
122120 putenv ('NFSE_PFX_PASS ' );
123121
@@ -130,6 +128,30 @@ private function repackLegacyPfx(string $pfxContent, string $password): string
130128 }
131129 }
132130
131+ /**
132+ * @return array{string, string} [privateKeyPem, certificatePem]
133+ */
134+ private function extractPemParts (string $ pemBundle , string $ cnpj ): array
135+ {
136+ $ privateKeyMatched = preg_match (
137+ '/-----BEGIN(?: ENCRYPTED)? PRIVATE KEY-----.*?-----END(?: ENCRYPTED)? PRIVATE KEY-----/s ' ,
138+ $ pemBundle ,
139+ $ privateKeyMatches ,
140+ ) === 1 ;
141+
142+ $ certificateMatched = preg_match (
143+ '/-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----/s ' ,
144+ $ pemBundle ,
145+ $ certificateMatches ,
146+ ) === 1 ;
147+
148+ if (!$ privateKeyMatched || !$ certificateMatched ) {
149+ throw new PfxImportException ('Failed to extract PEM material from legacy PFX for CNPJ ' . $ cnpj );
150+ }
151+
152+ return [$ privateKeyMatches [0 ], $ certificateMatches [0 ]];
153+ }
154+
133155 /**
134156 * Signs an XML document per ABRASF 2.04 / XML-DSig (RSA-SHA1, enveloped signature).
135157 *
0 commit comments