lib/rubygems/security/policy.rb
##
# Verify that the gem data with the given signature and signing chain
# matched this security policy at the specified time.
Verify that the gem data with the given signature and signing chain
matched this security policy at the specified time.
Verify that the gem data with the given signature and signing chain matched this security policy at the specified time .
def verify_signature signature, data, chain, time = Time.now
    Gem.ensure_ssl_available
    cert_class = OpenSSL::X509::Certificate
    exc = Gem::Security::Exception
    chain ||= []
    chain = chain.map{ |str| cert_class.new(str) }
    signer, ch_len = chain[-1], chain.size
    opt = Gem::Security::OPT.merge(@opt)
    if @verify_data
      dgst = opt[:dgst_algo]
      v = signer.public_key.verify(dgst.new, signature, data)
      raise exc, "Invalid Gem Signature" unless v
      if @verify_signer
        v = signer.check_validity(nil, time)
        raise exc, "Invalid Signature: #{v[:desc]}" unless v[:is_valid]
      end
    end
    if @verify_chain
      (ch_len - 1).downto(1) do |i|
        issuer, cert = chain[i - 1, 2]
        v = cert.check_validity(issuer, time)
        raise exc, "%s: cert = '%s', error = '%s'" % [
            'Invalid Signing Chain', cert.subject, v[:desc]
        ] unless v[:is_valid]
      end
      if @verify_root
        root = chain[0]
        raise exc, "%s: %s (subject = '%s', issuer = '%s')" % [
            'Invalid Signing Chain Root',
            'Subject does not match Issuer for Gem Signing Chain',
            root.subject.to_s,
            root.issuer.to_s,
        ] unless root.issuer.to_s == root.subject.to_s
        v = root.check_validity(root, time)
        raise exc, "%s: cert = '%s', error = '%s'" % [
            'Invalid Signing Chain Root', root.subject, v[:desc]
        ] unless v[:is_valid]
        if @only_trusted
          algo = opt[:dgst_algo]
          path = Gem::Security::Policy.trusted_cert_path(root, opt)
          raise exc, "%s: cert = '%s', error = '%s'" % [
              'Untrusted Signing Chain Root',
              root.subject.to_s,
              "path \"#{path}\" does not exist",
          ] unless File.exist?(path)
          save_cert = OpenSSL::X509::Certificate.new(File.read(path))
          save_dgst = algo.digest(save_cert.public_key.to_s)
          pkey_str = root.public_key.to_s
          cert_dgst = algo.digest(pkey_str)
          raise exc, "%s: %s (saved = '%s', root = '%s')" % [
              'Invalid Signing Chain Root',
              "Saved checksum doesn't match root checksum",
              save_dgst, cert_dgst,
          ] unless save_dgst == cert_dgst
        end
      end
      chain.map { |cert| cert.subject }
    end
  end
def verify_signature signature , data , chain , time = Time . now Gem . ensure_ssl_available cert_class = OpenSSL :: X509 :: Certificate exc = Gem :: Security :: Exception chain ||= [ ] chain = chain . map { | str | cert_class . new ( str ) } signer , ch_len = chain [ - 1 ] , chain . size opt = Gem :: Security :: OPT . merge ( @opt ) if @verify_data dgst = opt [ :dgst_algo ] v = signer . public_key . verify ( dgst . new , signature , data ) raise exc , "Invalid Gem Signature" unless v if @verify_signer v = signer . check_validity ( nil , time ) raise exc , "Invalid Signature: #{v[:desc]}" unless v [ :is_valid ] end end if @verify_chain ( ch_len - 1 ) . downto ( 1 ) do | i | issuer , cert = chain [ i - 1 , 2 ] v = cert . check_validity ( issuer , time ) raise exc , "%s: cert = '%s', error = '%s'" % [ 'Invalid Signing Chain' , cert . subject , v [ :desc ] ] unless v [ :is_valid ] end if @verify_root root = chain [ 0 ] raise exc , "%s: %s (subject = '%s', issuer = '%s')" % [ 'Invalid Signing Chain Root' , 'Subject does not match Issuer for Gem Signing Chain' , root . subject . to_s , root . issuer . to_s , ] unless root . issuer . to_s == root . subject . to_s v = root . check_validity ( root , time ) raise exc , "%s: cert = '%s', error = '%s'" % [ 'Invalid Signing Chain Root' , root . subject , v [ :desc ] ] unless v [ :is_valid ] if @only_trusted algo = opt [ :dgst_algo ] path = Gem :: Security :: Policy . trusted_cert_path ( root , opt ) raise exc , "%s: cert = '%s', error = '%s'" % [ 'Untrusted Signing Chain Root' , root . subject . to_s , "path \"#{path}\" does not exist" , ] unless File . exist? ( path ) save_cert = OpenSSL :: X509 :: Certificate . new ( File . read ( path ) ) save_dgst = algo . digest ( save_cert . public_key . to_s ) pkey_str = root . public_key . to_s cert_dgst = algo . digest ( pkey_str ) raise exc , "%s: %s (saved = '%s', root = '%s')" % [ 'Invalid Signing Chain Root' , "Saved checksum doesn't match root checksum" , save_dgst , cert_dgst , ] unless save_dgst == cert_dgst end end chain . map { | cert | cert . subject } end end
Verify that the gem data with the given signature and signing chain
matched this security policy at the specified time.
Verify that the gem data with the given signature and signing chain matched this security policy at the specified time .
# make sure signature is valid # get digest algorithm (TODO: this should be configurable) # verify the data signature (this is the most important part, so don't # screw it up :D) # make sure the signer is valid # make sure the signing cert is valid right now # make sure the certificate chain is valid # iterate down over the chain and verify each certificate against it's # issuer # verify root of chain # make sure root is self-signed # make sure root is valid # verify that the chain root is trusted # get digest algorithm, calculate checksum of root.subject # check to make sure trusted path exists # load calculate digest from saved cert file # create digest of public key # now compare the two digests, raise exception # if they don't match # return the signing chain
signature
data
chain
time
now