ruby/ruby · error · Gem::Security::Exception

trusted root certificate #{root.subject} checksum does not m

Error message

trusted root certificate #{root.subject} checksum does not match signing root certificate checksum

What it means

check_trust found a trusted certificate file for the root's subject in the trust dir, but the digest (default SHA-256) of the saved certificate's public key differs from the digest of the root in the gem's chain. 'trusted root certificate ... checksum does not match signing root certificate checksum' means the stored trusted copy and the presented root share identity but not key material — the root was re-issued/re-generated under the same subject, so the old trust entry no longer corresponds.

Source

Thrown at lib/rubygems/security/policy.rb:173

    path = Gem::Security.trust_dir.cert_path root

    unless File.exist? path
      message = "root cert #{root.subject} is not trusted".dup

      message << " (root of signing cert #{chain.last.subject})" if
        chain.length > 1

      raise Gem::Security::Exception, message
    end

    save_cert = OpenSSL::X509::Certificate.new File.read path
    save_dgst = digester.digest save_cert.public_key.public_to_pem

    pkey_str = root.public_key.public_to_pem
    cert_dgst = digester.digest pkey_str

    raise Gem::Security::Exception,
          "trusted root certificate #{root.subject} checksum " \
          "does not match signing root certificate checksum" unless
      save_dgst == cert_dgst

    true
  end

  ##
  # Extracts the email or subject from +certificate+

  def subject(certificate) # :nodoc:
    certificate.extensions.each do |extension|
      next unless extension.oid == "subjectAltName"

      return extension.value
    end

    certificate.subject.to_s

View on GitHub (pinned to 0e5b888e1c)

Solutions

  1. Update the trust entry: remove the stale certificate from the trust dir and add the current one — `gem cert --list`, `gem cert --remove <subject>`, then `gem cert --add new_root.pem`
  2. Get the new root cert from the gem author's authoritative source (verify out-of-band before trusting)
  3. If you manage the CA: avoid re-issuing under the same subject with new keys; prefer a new subject or keep the key

Example fix

# refresh stale trust entry
gem cert --remove '/CN=old-root/...'
gem cert --add new-gem-public_cert.pem
gem install signed-gem -P HighSecurity
Defensive patterns

Strategy: fallback

Validate before calling

saved = OpenSSL::X509::Certificate.new(File.read(Gem::Security.trust_dir.cert_path(chain.first)))
needs_refresh = Gem::Security.create_digest.digest(saved.public_key.public_to_pem) != Gem::Security.create_digest.digest(chain.first.public_key.public_to_pem)

Type guard

def trust_entry_current?(root)
  path = Gem::Security.trust_dir.cert_path(root)
  return false unless File.exist?(path)
  saved = OpenSSL::X509::Certificate.new(File.read(path))
  saved.public_key.public_to_pem == root.public_key.public_to_pem
end

Try / catch

begin
  Gem::Package.new(gem_path, Gem::Security::Policies['HighSecurity']).verify
rescue Gem::Security::Exception => e
  refresh_trust_entry(root_cert) if e.message.include?('checksum')
end

Prevention

When it happens

Trigger: Author regenerated their root key+cert (same subject/email) after losing the old one; your trust dir still holds the previous certificate; a re-issued CA cert with identical subject but a new key. Check `Gem::Security.trust_dir.cert_path(root)` file exists, then digests diverge.

Common situations: Lost CA keys followed by `gem cert --build` re-creation; certificate renewal that changes the key; importing a different organization's cert with the same subject string.

Understand the failure class

Related errors


AI-assisted analysis of ruby/ruby@0e5b888e1c (2026-08-21). Data as JSON: /api/errors/5aec0277d2eae76b. Report an issue: GitHub.