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 + -
显示快捷键?