puppetlabs/puppet · error · OpenSSL::X509::CRLError

Failed to parse CRLs as PEM

Error message

Failed to parse CRLs as PEM

What it means

CertProvider#load_crls_from_pem raises OpenSSL::X509::CRLError when the CRL text contains no '-----BEGIN X509 CRL-----' block (CRL_DELIMITERS fails to match), and the same class surfaces from OpenSSL::X509::CRL.new for a block that is present but malformed. The CRL is unusable, so revocation checking and the SSL context fail.

Source

Thrown at lib/puppet/x509/cert_provider.rb:124

    if !pem && required
      raise Puppet::Error, _("The CRL is missing from '%{path}'") % { path: @crlpath }
    end

    pem ? load_crls_from_pem(pem) : nil
  rescue SystemCallError => e
    raise Puppet::Error.new(_("Failed to load CRLs from '%{crlpath}'") % { crlpath: @crlpath }, e)
  end

  # Load PEM encoded CRL(s).
  #
  # @param pem [String] PEM encoded CRL(s)
  # @return [Array<OpenSSL::X509::CRL>] Array of CRLs
  # @raise [OpenSSL::X509::CRLError] The `pem` text does not contain a valid CRL
  #
  # @api private
  def load_crls_from_pem(pem)
    # TRANSLATORS 'PEM' is an acronym and shouldn't be translated
    raise OpenSSL::X509::CRLError, _("Failed to parse CRLs as PEM") if pem !~ CRL_DELIMITERS

    pem.scan(CRL_DELIMITERS).map do |text|
      OpenSSL::X509::CRL.new(text)
    end
  end

  # Return the time when the CRL was last updated.
  #
  # @return [Time, nil] Time when the CRL was last updated, or nil if we don't
  #   have a CRL
  #
  # @api private
  def crl_last_update
    stat = Puppet::FileSystem.stat(@crlpath)
    Time.at(stat.mtime)
  rescue Errno::ENOENT
    nil
  end

View on GitHub (pinned to e227c27540)

Solutions

  1. Inspect: `openssl crl -in crl.pem -noout -text` must show a CRL, not a certificate or garbage
  2. Convert DER to PEM: `openssl crl -inform der -in crl.der -outform pem -out crl.pem`
  3. Delete the bad file and rerun `puppet agent -t` to refetch it
  4. Re-publish the CRL on the CA if the published file itself is broken

Example fix

# before
$ openssl crl -in crl.pem -noout
unable to load CRL

# after
$ openssl crl -inform der -in crl.der -outform pem -out crl.pem
$ openssl crl -in crl.pem -noout
Defensive patterns

Strategy: validation

Validate before calling

def pem_crl?(path)
  File.read(path).match?(/-----BEGIN X509 CRL-----/)
end

raise 'crl.pem is not PEM' unless pem_crl?(Puppet[:hostcrl])

Try / catch

begin
  crls = provider.load_crls(required: true)
rescue OpenSSL::X509::CRLError => e
  abort "CRL at #{Puppet[:hostcrl]} is malformed: #{e.message} — refetch with `puppet agent -t`"
end

Prevention

When it happens

Trigger: crl.pem truncated by an interrupted download; DER binary saved with a .pem name; a certificate block saved into crl.pem by mistake; file corruption from disk issues or editors rewriting the file.

Common situations: Interrupted first agent run; scripts generating the CRL with `openssl crl -outform der`; config management that templates or rewrites the CRL incorrectly.

Understand the failure class

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/692cbf9971270f71. Report an issue: GitHub.