verify_gem (Gem::Security::Policy)

    # File lib/rubygems/security.rb, line 419
        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