Zend Http Client SSL certificate validation failure with custom CA bundles
27K reputation · 28 Jun 2024, 06:04 UTC
The Zend\Http\Client (Laminas) relies on PHP stream wrappers to handle SSL/TLS handshakes. When configuring the client for secure communication, the sslcafile and sslcapath options are used to define the trusted Certificate Authority bundles for peer verification.
There is uncertainty regarding the precedence of these client-level configurations when the php.ini setting openssl.cafile is also defined. Specifically, it is unclear if the client-specific options completely override the global PHP configuration or if the underlying OpenSSL extension merges these paths during the validation process.
- Does the
sslcafileoption in the client configuration take absolute precedence over theopenssl.cafiledirective inphp.ini? - In environments where
verify_peeris enabled, how does the client behave if thesslcafileis provided but the system-level CA bundle is missing?
1 answer
1 question comment
Use comments to ask for clarification. Post a solution as an answer.
27,025 reputation · 28 Jun 2024, 07:45 UTC
Precedence of CA bundle settings
The Zend Http Client passes the CA bundle path it receives (via sslcafile or sslcapath) directly to the underlying PHP stream context or cURL. When that value is set, the client never consults the openssl.cafile directive from php.ini. Only if the client omits a custom bundle will PHP fall back to the global setting.
Required format and ordering
For the bundle to be accepted:
- It must be a PEM‑encoded file.
- The certificates should be concatenated in the order leaf → intermediate(s) → root (the order matters for chain building).
- The file must be readable by the user running the PHP process; otherwise the handshake fails with "certificate verify failed".
If the server presents a self‑signed certificate that you trust, set allowSelfSigned to true and keep sslVerifyPeerName enabled to avoid hostname spoofing.
Quick test snippet
$client = new Zend\Http\Client('https://example.com');
$client->setOptions([
'ssl' => [
'verify_peer' => true,
'verify_peer_name' => true,
'allow_self_signed' => false,
'cafile' => '/path/to/ca-bundle.pem',
],
]);
$response = $client->send();
Validate the setup
- Run
php -i | grep opensslto confirm the OpenSSL extension is enabled. - Check
phpinfo()for theopenssl.cafilevalue to see the global fallback. - Use
openssl s_client -connect example.com:443 -CAfile /path/to/ca-bundle.pemto verify the chain outside PHP.