paragonie/certainty
Automate and manage cacert.pem for PHP projects to ensure reliable TLS certificate validation across diverse environments. Avoid disabling verification, reduce support burden, and keep HTTP clients secure. Requires PHP 8.3+.
Installation:
composer require paragonie/certainty:^3
Requires PHP 8.3+ (or use ^2 for PHP < 8.3).
First Use Case: Fetch the latest CA bundle in a Laravel HTTP client (e.g., Guzzle):
use ParagonIE\Certainty\RemoteFetch;
$fetch = new RemoteFetch();
$bundlePath = $fetch->getLatestBundle(); // Returns path to verified cacert.pem
Where to Look First:
RemoteFetch usage).Runtime Fetching (Recommended):
// Laravel Service Provider (e.g., AppServiceProvider)
public function boot()
{
$bundlePath = (new RemoteFetch())->getLatestBundle();
config(['http.connections.guzzle.options' => [
'curl' => [
CURLOPT_CAINFO => $bundlePath,
],
]]);
}
Composer Pre-Update (Optimized):
Add to composer.json:
{
"scripts": {
"post-autoload-dump": [
"ParagonIE\\Certainty\\Composer::postAutoloadDump"
]
}
}
$bundlePath = (new \ParagonIE\Certainty\Fetch())->getLatestBundle();
composer update to stay current.Custom Data Directory:
$fetch = new RemoteFetch('/custom/path/to/certs');
$bundlePath = $fetch->getLatestBundle();
Laravel HTTP Clients: Bind the bundle path to a config value and inject it into Guzzle/HTTP clients:
$client = Http::withOptions([
'curl' => [
CURLOPT_CAINFO => config('certainty.bundle_path'),
],
]);
Trust Channels: Filter bundles by trust channel (e.g., "Mozilla") for enterprise use:
$fetch = new RemoteFetch();
$bundle = $fetch->getBundle('2025-09-09', 'Mozilla');
Fallback Servers: Configure a replica Chronicle URL for high availability:
$fetch = new RemoteFetch(null, 'https://replica.pie-hosted.net');
Caching:
Cache the bundle path in Laravel’s cache (e.g., Redis) to avoid repeated RemoteFetch calls:
$bundlePath = Cache::remember('certainty.bundle_path', now()->addDays(7), function () {
return (new RemoteFetch())->getLatestBundle();
});
PHP < 8.3:
^2 branch (e.g., paragonie/certainty:^2) for legacy support.Offline Environments:
RemoteFetch fails without internet. Use Fetch with pre-downloaded bundles:
$fetch = new \ParagonIE\Certainty\Fetch('/path/to/pre-downloaded/bundle');
Composer Lockfile:
certainty to a specific version (e.g., 3.0.2). Use ^3 to auto-update bundles.RemoteFetch workflows (e.g., air-gapped systems).Chronicle Failures:
php-chronicle.pie-hosted.com is down, switch to a replica:
$fetch = new RemoteFetch(null, 'https://replica.pie-hosted.net');
32-bit Systems:
$fetch = new RemoteFetch();
$fetch->setVerifySignatures(false); // Not recommended for production
Verify Bundle Integrity:
$fetch = new RemoteFetch();
$bundle = $fetch->getBundle(); // Returns full bundle data with metadata
var_dump($bundle->getSha256()); // Checksum
var_dump($bundle->getSignature()); // Ed25519 signature
Log Failures:
Enable verbose logging for RemoteFetch:
$fetch = new RemoteFetch();
$fetch->setLogger(new \Monolog\Logger('certainty', [new \Monolog\Handler\StreamHandler(storage_path('logs/certainty.log'))]));
Check for Stale Bundles: Compare local bundle timestamps with the latest release:
composer show paragonie/certainty | grep -E "version|time"
Custom Bundle Sources:
Extend ParagonIE\Certainty\Fetch to support internal CA repositories:
class InternalFetch extends \ParagonIE\Certainty\Fetch {
public function getLatestBundle() {
return '/path/to/internal/cacert.pem';
}
}
Override Chronicle URL: For enterprise isolation, host your own Chronicle instance:
$fetch = new RemoteFetch(null, 'https://your-chronicle.example.com');
Add Trust Channels:
Extend the TrustChannel enum for custom channels (e.g., "Internal"):
namespace App\Certainty;
use ParagonIE\Certainty\TrustChannel;
class CustomTrustChannel extends TrustChannel {
public const INTERNAL = 'Internal';
}
Hook into Bundle Updates:
Listen for post-autoload-dump events to trigger custom logic:
// composer.json
{
"scripts": {
"post-autoload-dump": [
"ParagonIE\\Certainty\\Composer::postAutoloadDump",
"@custom-cert-script"
]
}
}
Avoid Repeated Fetches: Cache the bundle path in Laravel’s cache or session:
$bundlePath = Cache::rememberForever('certainty.bundle_path', function () {
return (new RemoteFetch())->getLatestBundle();
});
Use Fetch in Production:
Pre-download bundles via CI/CD and use Fetch in production to eliminate runtime network calls:
# In CI/CD pipeline
composer require paragonie/certainty:^3
vendor/bin/certainty-update
Parallelize Updates:
For monorepos or large projects, run composer update in parallel with:
composer update --no-plugins --no-scripts && composer update
How can I help you explore Laravel packages today?