Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ssl Certificate Chain Resolver Laravel Package

spatie/ssl-certificate-chain-resolver

Resolves incomplete SSL certificate chains by discovering and returning the missing intermediate certificates between a site’s cert and trusted roots. Helps fix “Extra download” issues flagged by SSL Labs, improving compatibility for mobile and strict clients.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require spatie/ssl-certificate-chain-resolver
    

    No additional configuration is required—just autoload the package.

  2. First Use Case: Resolving Certificate Chains

    use Spatie\SslCertificateChainResolver\Facades\SslCertificateChainResolver;
    
    $resolver = new \Spatie\SslCertificateChainResolver\SslCertificateChainResolver();
    $chain = $resolver->resolve('https://example.com');
    
    • Output: Returns an array of certificates (PEM format) in the correct order, including intermediates.
  3. Where to Look First

    • Facade: Spatie\SslCertificateChainResolver\Facades\SslCertificateChainResolver for quick usage.
    • Resolver Class: \Spatie\SslCertificateChainResolver\SslCertificateChainResolver for custom logic.
    • Tests: Test file for edge cases.

Implementation Patterns

Common Workflows

1. Generating Full Certificate Chains for Web Servers

$resolver = new \Spatie\SslCertificateChainResolver\SslCertificateChainResolver();
$chain = $resolver->resolve('https://example.com');

// Save to a file (e.g., for Nginx/Apache)
file_put_contents('/etc/ssl/certs/example.com-chain.pem', implode(PHP_EOL, $chain));
  • Use Case: Automate certificate chain updates in CI/CD pipelines (e.g., deploy scripts).

2. Validating Certificate Chains Programmatically

$resolver = new \Spatie\SslCertificateChainResolver\SslCertificateChainResolver();
$chain = $resolver->resolve('https://example.com');

if (count($chain) === 0) {
    throw new \RuntimeException('No valid certificate chain found!');
}
  • Use Case: Pre-flight checks in Laravel middleware or service providers.

3. Integrating with Laravel HTTP Clients

use Illuminate\Support\Facades\Http;
use Spatie\SslCertificateChainResolver\Facades\SslCertificateChainResolver;

$url = 'https://example.com';
$chain = SslCertificateChainResolver::resolve($url);

// Use the chain with Guzzle (if needed)
$client = Http::withOptions([
    'curl' => [
        'SSLCERT' => tempnam(sys_get_temp_dir(), 'chain_') . '.pem',
    ],
])->post($url, ['data' => 'test']);

// Cleanup
unlink($tempCertPath);
  • Note: Directly passing the chain to Laravel’s HTTP client isn’t supported, but you can use it with underlying Guzzle.

4. Caching Resolved Chains

$cacheKey = 'ssl_chain_example_com';
$chain = cache()->remember($cacheKey, now()->addHours(1), function () {
    return SslCertificateChainResolver::resolve('https://example.com');
});
  • Use Case: Avoid repeated network calls in high-traffic applications.

Integration Tips

With Laravel Queues

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Spatie\SslCertificateChainResolver\Facades\SslCertificateChainResolver;

class ResolveCertificateChain implements ShouldQueue
{
    use Queueable;

    public function handle()
    {
        $chain = SslCertificateChainResolver::resolve('https://example.com');
        // Save to storage or database
    }
}
  • Why: Offload chain resolution during low-traffic periods.

With Laravel Artisan Commands

use Illuminate\Console\Command;
use Spatie\SslCertificateChainResolver\Facades\SslCertificateChainResolver;

class UpdateCertificates extends Command
{
    protected $signature = 'certificates:update {url}';
    protected $description = 'Update SSL certificate chain for a domain';

    public function handle()
    {
        $chain = SslCertificateChainResolver::resolve($this->argument('url'));
        file_put_contents(storage_path("app/{$this->argument('url')}-chain.pem"), implode(PHP_EOL, $chain));
        $this->info('Certificate chain updated!');
    }
}
  • Why: Schedule via Laravel’s task scheduler (schedule:run).

With Laravel Service Providers

use Illuminate\Support\ServiceProvider;
use Spatie\SslCertificateChainResolver\SslCertificateChainResolver;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton('ssl.resolver', function () {
            return new SslCertificateChainResolver();
        });
    }
}
  • Why: Centralize resolver instance for dependency injection.

Gotchas and Tips

Pitfalls

  1. Network Timeouts

    • The resolver makes HTTP requests to fetch certificates. Timeout errors may occur for slow/unreachable hosts.
    • Fix: Set a custom timeout:
      $resolver = new \Spatie\SslCertificateChainResolver\SslCertificateChainResolver();
      $resolver->setTimeout(5); // 5 seconds
      
  2. Self-Signed Certificates

    • The resolver may fail on self-signed certificates or private CAs.
    • Fix: Use resolveWithOptions() to bypass validation:
      $chain = $resolver->resolveWithOptions('https://self-signed.example', [
          'verify_peer' => false,
      ]);
      
      Warning: Only use this for trusted internal systems.
  3. Rate Limiting

    • Some Certificate Authorities (e.g., Let’s Encrypt) may block rapid requests.
    • Fix: Implement caching or exponential backoff.
  4. PEM Format Assumptions

    • The package returns certificates in PEM format. Some systems (e.g., Java) require DER.
    • Fix: Convert using OpenSSL:
      $derCert = openssl_csr_export($pemCert, 'DER');
      

Debugging Tips

  1. Enable Verbose Output

    $resolver = new \Spatie\SslCertificateChainResolver\SslCertificateChainResolver();
    $resolver->setVerbose(true); // Logs HTTP requests/responses
    $chain = $resolver->resolve('https://example.com');
    
  2. Inspect Raw Responses

    $resolver = new \Spatie\SslCertificateChainResolver\SslCertificateChainResolver();
    $response = $resolver->getResponse('https://example.com');
    // $response contains the raw HTTP response object
    
  3. Check for OCSP Stapling Issues

    • Some chains fail due to OCSP stapling. Disable it temporarily:
      $chain = $resolver->resolveWithOptions('https://example.com', [
          'ssl' => [
              'disable_ocsp' => true,
          ],
      ]);
      

Extension Points

  1. Custom Certificate Stores

    • Override the default CA store (e.g., for custom root CAs):
      $resolver = new \Spatie\SslCertificateChainResolver\SslCertificateChainResolver();
      $resolver->setCaStore('/path/to/custom/cacert.pem');
      
  2. Extending the Resolver Class

    • Subclass to add pre/post-processing:
      class CustomResolver extends \Spatie\SslCertificateChainResolver\SslCertificateChainResolver
      {
          public function resolve($url)
          {
              $chain = parent::resolve($url);
              // Add custom logic (e.g., filter specific CAs)
              return array_filter($chain, fn($cert) => str_contains($cert, 'Let\'s Encrypt'));
          }
      }
      
  3. Hooking into HTTP Requests

    • Use the beforeResolve and afterResolve events (if the package supports them) or wrap the resolver:
      $resolver = new \Spatie\SslCertificateChainResolver\SslCertificateChainResolver();
      $resolver->beforeResolve(function ($url) {
          Log::info("Resolving chain for: {$url}");
      });
      

Configuration Quirks

  1. Environment-Specific Settings

    • The resolver respects Laravel’s .env for timeout and CA store paths:
      SSL_CERTIFICATE_CHAIN_RESOLVER_TIMEOUT=10
      SSL_CERTIFICATE_CHAIN_RESOLVER_CA_STORE=/etc/ssl/certs/ca-certificates.crt
      
    • Note: These must be manually loaded in your resolver instance.
  2. Proxy Support

    • If behind a proxy, configure the underlying Guzzle client:
      $resolver = new \Spatie\SslCertificateChain
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport