# File lib/rubygems/security.rb, line 159
      def verify_gem(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

        # make sure signature is valid
        if @verify_data
          # get digest algorithm (TODO: this should be configurable)
          dgst = @opt[:dgst_algo]

          # verify the data signature (this is the most important part,
          # so don't screw it up :D)
          v = signer.public_key.verify(dgst.new, signature, data)
          raise exc, "Invalid Gem Signature" unless v
          
          # make sure the signer is valid
          if @verify_signer
            # make sure the signing cert is valid right now
            v = signer.check_validity(nil, time)
            raise exc, "Invalid Signature: #{v[:desc]}" unless v[:is_valid]
          end
        end

        # make sure the certificate chain is valid
        if @verify_chain
          # iterate down over the chain and verify each certificate
          # against it's issuer
          (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

          # verify root of chain
          if @verify_root
            # make sure root is self-signed
            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

            # make sure root is valid
            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]

            # verify that the chain root is trusted
            if @only_trusted
              # get digest algorithm, calculate checksum of root.subject
              algo = @opt[:dgst_algo]
              path = Gem::Security::Policy.trusted_cert_path(root, @opt)

              # check to make sure trusted path exists
              raise exc, "%s: cert = '%s', error = '%s'" % [
                'Untrusted Signing Chain Root',
                root.subject.to_s,
                "path \"#{path}\" does not exist",
              ] unless File.exist?(path)

              # load calculate digest from saved cert file
              save_cert = OpenSSL::X509::Certificate.new(File.read(path))
              save_dgst = algo.digest(save_cert.public_key.to_s)

              # create digest of public key
              pkey_str = root.public_key.to_s
              cert_dgst = algo.digest(pkey_str)

              # now compare the two digests, raise exception
              # if they don't match
              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

          # return the signing chain
          chain.map { |cert| cert.subject } 
        end
      end