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+.
cacert.pem management in Laravel, aligning with Laravel’s HTTP client (Guzzle) and cURL-based dependencies. It eliminates hardcoded paths (e.g., /etc/ssl/certs/ca-certificates.crt) and replaces them with a verifiable, auto-updating bundle.curl_setopt(CURLOPT_CAINFO, ...)) with a single use statement and RemoteFetch initialization.
use ParagonIE\Certainty\RemoteFetch;
$fetch = new RemoteFetch();
$caBundle = $fetch->getLatestBundle();
Http facade or Guzzle clients by passing the bundle path:
$client = new \GuzzleHttp\Client(['ca_info' => $caBundle->getPath()]);
ca_info option.| Risk Area | Mitigation Strategy |
|---|---|
| Dependency Bloat | Minimal runtime overhead (only fetches updates when needed). Use Fetch (local) for pre-downloaded bundles. |
| PHP 8.3+ Requirement | Blocking for new Laravel projects (Laravel 10+). For older Laravel, use paragonie/certainty:^2. |
| Network Dependency | Fallback to local cache if Chronicle/remote fetch fails (configurable timeout). |
| Signature Verification | Ed25519-signed bundles prevent tampering; rotate keys if ParagonIE’s key is compromised. |
| Path Permissions | Defaults to sys_get_temp_dir(); customize with setDataDirectory(). |
RemoteFetch is blocked? If so, use Fetch with manual updates.composer post-autoload-dump (via Composer::postAutoloadDump) be enabled to auto-update bundles on deploy?RemoteFetch is used.paragonie/certainty:^2 vs. custom CA management.App\Jobs\FetchRemoteData) where TLS failures are unacceptable.ext-curl (Laravel’s default) and ext-openssl.libsodium for Ed25519 verification (fallback to sodium_compat if missing).| Step | Action | Laravel-Specific Notes |
|---|---|---|
| 1. Add Dependency | composer require paragonie/certainty:^3 |
|
| 2. Configure | Initialize RemoteFetch in a service provider or config file. |
Example: config/certainty.php with data_directory and chronicle_url. |
| 3. Replace Hardcoded Paths | Update HTTP clients to use $caBundle->getPath(). |
For Guzzle: $client = new Client(['ca_info' => $caBundle->getPath()]). |
| 4. Test Edge Cases | Verify behavior in: |
cacert.pem).RemoteFetch latency. |
| 5. Optional: Auto-Update | Add to composer.json:"scripts": {
"post-autoload-dump": ["ParagonIE\\Certainty\\Composer::postAutoloadDump"]
}
``` | Ensures bundles update on `composer install/update`. |
### **Compatibility**
- **Laravel Versions**:
- **Laravel 10+ (PHP 8.3+)**: Full feature support (use `^3`).
- **Laravel 9/8 (PHP 8.1–8.2)**: Use `paragonie/certainty:^2` (deprecated but compatible).
- **Laravel <8 (PHP <8.1)**: Avoid; use custom CA management or upgrade.
- **Third-Party Packages**: Conflicts unlikely, but test with:
- `guzzlehttp/guzzle` (v7+ recommended).
- `symfony/http-client` (if used directly).
- `reactphp/http` (if using ReactPHP for async requests).
### **Sequencing**
1. **Phase 1 (Low Risk)**: Replace CA paths in **non-critical** HTTP calls (e.g., analytics, logging).
2. **Phase 2 (Medium Risk)**: Update **internal APIs** (e.g., service-to-service calls).
3. **Phase 3 (High Risk)**: Secure **user-facing TLS** (e.g., payment processing, OAuth).
4. **Phase 4 (Optional)**: Enable `Composer::postAutoloadDump` for auto-updates.
---
## Operational Impact
### **Maintenance**
- **Update Frequency**:
- **Library**: Update `paragonie/certainty` **quarterly** (or via `post-autoload-dump`).
- **CA Bundles**: Auto-updated via `RemoteFetch` (no manual intervention).
- **Monitoring**:
- Log `RemoteFetch` failures (e.g., network timeouts, signature mismatches).
- Alert on **bundle age** (e.g., >7 days old in production).
- **Rollback Plan**:
- Fallback to a **local bundle** (`Fetch` class) if `RemoteFetch` fails.
- Pin to a specific bundle version if Chronicle is unavailable.
### **Support**
- **Troubleshooting**:
- **Common Issues**:
- **Permission Denied**: Set `data_directory` to a writable path (e.g., `storage/app/certainty`).
- **Network Errors**: Increase `setConnectionTimeout()` (default: 5s).
- **Signature Failures**: Verify `libsodium` is installed (`pecl install libsodium`).
- **Debugging Tools**:
- `RemoteFetch::getLatestBundle(verbose: true)` for logs.
- `Certainty::getAllAvailableBundles()` to inspect local cache.
- **Support Contracts**:
- ParagonIE offers **enterprise support** for critical use cases (e.g., financial systems).
### **Scaling**
- **Performance**:
- **First Run**: ~200ms (download + verify bundle).
- **Subsequent Runs**: ~50ms (cache hit).
- **High-Volume**: Use `Fetch` (local) + cron job for updates to avoid runtime overhead.
- **Concurrency**:
- Thread-safe for multi-process environments (e.g., Laravel queues).
- **Not thread-safe** in PHP-FPM; use a single instance per request.
- **Storage**:
- Bundles are **~1MB** each; cache up to 3 versions by default.
### **Failure Modes**
| Failure Scenario | Impact | Mitigation |
|--------------------------------|---------------------------------|-----------------------------------------------------------------------------|
| **Chronicle Unavailable** | Bundle updates stall. | Fallback to local cache or manual update. |
| **Network Timeout** | TLS validation fails. | Increase timeout or use `Fetch` with pre-downloaded bundles. |
| **Signature Mismatch** | Tampered bundle detected. | Alert security team; investigate key compromise. |
| **Disk Full** | Bundle download fails. | Set `data_directory` to a larger volume or clean old bundles. |
| **PHP <8.3** | Library incompatible. | Downgrade to `paragonie/certainty:^2` or upgrade PHP. |
### **Ramp-Up**
- **Developer Onboarding**:
How can I help you explore Laravel packages today?