security.rb

来自「Amarok是一款在LINUX或其他类UNIX操作系统中运行的音频播放器软件。 」· RB 代码 · 共 485 行 · 第 1/2 页

RB
485
字号
#!/usr/bin/env ruby#--# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.# All rights reserved.# See LICENSE.txt for permissions.#++require 'rubygems/gem_openssl'module Gem  module SSL    # We make our own versions of the constants here.  This allows us    # to reference the constants, even though some systems might not    # have SSL installed in the Ruby core package.    #    # These constants are only used during load time.  At runtime, any    # method that makes a direct reference to SSL software must be    # protected with a Gem.ensure_ssl_available call.    #    if Gem.ssl_available?      PKEY_RSA = OpenSSL::PKey::RSA      DIGEST_SHA1 = OpenSSL::Digest::SHA1    else      PKEY_RSA = :rsa      DIGEST_SHA1 = :sha1    end  endendmodule  OpenSSL  module X509    class Certificate      #      # Check the validity of this certificate.        #      def check_validity(issuer_cert = nil, time = Time.now)        ret = if @not_before && @not_before > time          [false, :expired, "not valid before '#@not_before'"]        elsif @not_after && @not_after < time          [false, :expired, "not valid after '#@not_after'"]        elsif issuer_cert && !verify(issuer_cert.public_key)          [false, :issuer, "#{issuer_cert.subject} is not issuer"]        else          [true, :ok, 'Valid certificate']        end        # return hash        { :is_valid => ret[0], :error => ret[1], :desc => ret[2] }      end    end  endendmodule Gem  #  # Security: a set of methods, classes, and security policies for  # checking the validity of signed gem files.  #  module Security    class Exception < Exception; end      #    # default options for most of the methods below    #    OPT = {      # private key options      :key_algo   => Gem::SSL::PKEY_RSA,      :key_size   => 2048,      # public cert options      :cert_age   => 365 * 24 * 3600, # 1 year      :dgst_algo  => Gem::SSL::DIGEST_SHA1,      # x509 certificate extensions      :cert_exts  => {        'basicConstraints'      => 'CA:FALSE',        'subjectKeyIdentifier'  => 'hash',        'keyUsage'              => 'keyEncipherment,dataEncipherment,digitalSignature',      },      # save the key and cert to a file in build_self_signed_cert()?      :save_key   => true,      :save_cert  => true,      # if you define either of these, then they'll be used instead of      # the output_fmt macro below      :save_key_path => nil,      :save_cert_path => nil,      # output name format for self-signed certs      :output_fmt => 'gem-%s.pem',      :munge_re   => Regexp.new(/[^a-z0-9_.-]+/),      # output directory for trusted certificate checksums      :trust_dir => File::join(Gem.user_home, '.gem', 'trust'),    }    #    # A Gem::Security::Policy object encapsulates the settings for    # verifying signed gem files.  This is the base class.  You can    # either declare an instance of this or use one of the preset    # security policies below.    #    class Policy      attr_accessor :verify_data, :verify_signer, :verify_chain,                     :verify_root, :only_trusted, :only_signed      #      # Create a new Gem::Security::Policy object with the given mode      # and options.      #      def initialize(policy = {}, opt = {})        # set options        @opt = Gem::Security::OPT.merge(opt)        # build policy        policy.each_pair do |key, val|          case key            when :verify_data   then @verify_data   = val            when :verify_signer then @verify_signer = val            when :verify_chain  then @verify_chain  = val            when :verify_root   then @verify_root   = val            when :only_trusted  then @only_trusted  = val            when :only_signed   then @only_signed   = val          end        end      end      #      # Get the path to the file for this cert.      #      def self.trusted_cert_path(cert, opt = {})        opt = Gem::Security::OPT.merge(opt)        # get digest algorithm, calculate checksum of root.subject        algo = opt[:dgst_algo]        dgst = algo.hexdigest(cert.subject.to_s)        # build path to trusted cert file        name = "cert-#{dgst}.pem"        # join and return path components        File::join(opt[:trust_dir], name)      end      #      # Verify that the gem data with the given signature and signing      # chain matched this security policy at the specified time.      #      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.exists?(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    end

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?