{"record":{"id":"692cbf9971270f71","repo":"puppetlabs/puppet","slug":"failed-to-parse-crls-as-pem","errorCode":null,"errorMessage":"Failed to parse CRLs as PEM","messagePattern":"Failed to parse CRLs as PEM","errorType":"exception","errorClass":"OpenSSL::X509::CRLError","httpStatus":null,"severity":"error","filePath":"lib/puppet/x509/cert_provider.rb","lineNumber":124,"sourceCode":"    if !pem && required\n      raise Puppet::Error, _(\"The CRL is missing from '%{path}'\") % { path: @crlpath }\n    end\n\n    pem ? load_crls_from_pem(pem) : nil\n  rescue SystemCallError => e\n    raise Puppet::Error.new(_(\"Failed to load CRLs from '%{crlpath}'\") % { crlpath: @crlpath }, e)\n  end\n\n  # Load PEM encoded CRL(s).\n  #\n  # @param pem [String] PEM encoded CRL(s)\n  # @return [Array<OpenSSL::X509::CRL>] Array of CRLs\n  # @raise [OpenSSL::X509::CRLError] The `pem` text does not contain a valid CRL\n  #\n  # @api private\n  def load_crls_from_pem(pem)\n    # TRANSLATORS 'PEM' is an acronym and shouldn't be translated\n    raise OpenSSL::X509::CRLError, _(\"Failed to parse CRLs as PEM\") if pem !~ CRL_DELIMITERS\n\n    pem.scan(CRL_DELIMITERS).map do |text|\n      OpenSSL::X509::CRL.new(text)\n    end\n  end\n\n  # Return the time when the CRL was last updated.\n  #\n  # @return [Time, nil] Time when the CRL was last updated, or nil if we don't\n  #   have a CRL\n  #\n  # @api private\n  def crl_last_update\n    stat = Puppet::FileSystem.stat(@crlpath)\n    Time.at(stat.mtime)\n  rescue Errno::ENOENT\n    nil\n  end","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/x509/cert_provider.rb#L106-L142","documentation":"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.","triggerScenarios":"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.","commonSituations":"Interrupted first agent run; scripts generating the CRL with `openssl crl -outform der`; config management that templates or rewrites the CRL incorrectly.","solutions":["Inspect: `openssl crl -in crl.pem -noout -text` must show a CRL, not a certificate or garbage","Convert DER to PEM: `openssl crl -inform der -in crl.der -outform pem -out crl.pem`","Delete the bad file and rerun `puppet agent -t` to refetch it","Re-publish the CRL on the CA if the published file itself is broken"],"exampleFix":"# before\n$ openssl crl -in crl.pem -noout\nunable to load CRL\n\n# after\n$ openssl crl -inform der -in crl.der -outform pem -out crl.pem\n$ openssl crl -in crl.pem -noout","handlingStrategy":"validation","validationCode":"def pem_crl?(path)\n  File.read(path).match?(/-----BEGIN X509 CRL-----/)\nend\n\nraise 'crl.pem is not PEM' unless pem_crl?(Puppet[:hostcrl])","typeGuard":null,"tryCatchPattern":"begin\n  crls = provider.load_crls(required: true)\nrescue OpenSSL::X509::CRLError => e\n  abort \"CRL at #{Puppet[:hostcrl]} is malformed: #{e.message} — refetch with `puppet agent -t`\"\nend","preventionTips":["Publish and fetch CRLs as PEM (`openssl crl -outform pem`)","Validate with `openssl crl -noout` in provisioning scripts before enabling revocation checking"],"tags":["ruby","puppet","ssl","openssl","pem","crl"],"backgroundTag":"malformed-pem-crl","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}