class Gem::Security::Policy
Gem::Security::Policy
对象封装了验证签名 gem 文件的设置。这是基类。你可以声明此类的实例,或者使用 Gem::Security::Policies 中预设的安全策略之一。
属性
name[R]
only_signed[RW]
only_trusted[RW]
to_s[R]
verify_chain[RW]
verify_data[RW]
verify_root[RW]
verify_signer[RW]
公共类方法
new(name, policy = {}, opt = {}) 点击切换源代码
使用给定的模式和选项创建一个新的 Gem::Security::Policy
对象。
# File rubygems/security/policy.rb, line 27 def initialize(name, policy = {}, opt = {}) @name = name @opt = opt # Default to security @only_signed = true @only_trusted = true @verify_chain = true @verify_data = true @verify_root = true @verify_signer = true 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
公共实例方法
check_cert(signer, issuer, time) 点击切换源代码
确保 signer
对于 time
有效,并且由 issuer
签名。如果 issuer
为 nil
,则不执行验证。
# File rubygems/security/policy.rb, line 86 def check_cert(signer, issuer, time) raise Gem::Security::Exception, "missing signing certificate" unless signer message = "certificate #{signer.subject}" if (not_before = signer.not_before) && not_before > time raise Gem::Security::Exception, "#{message} not valid before #{not_before}" end if (not_after = signer.not_after) && not_after < time raise Gem::Security::Exception, "#{message} not valid after #{not_after}" end if issuer && !signer.verify(issuer.public_key) raise Gem::Security::Exception, "#{message} was not issued by #{issuer.subject}" end true end
check_chain(chain, time) 点击切换源代码
验证 chain
中的每个证书都已签名后续证书,并且在给定的 time
内有效。
# File rubygems/security/policy.rb, line 56 def check_chain(chain, time) raise Gem::Security::Exception, "missing signing chain" unless chain raise Gem::Security::Exception, "empty signing chain" if chain.empty? begin chain.each_cons 2 do |issuer, cert| check_cert cert, issuer, time end true rescue Gem::Security::Exception => e raise Gem::Security::Exception, "invalid signing chain: #{e.message}" end end
check_data(public_key, digest, signature, data) 点击切换源代码
验证 data
是否与 public_key
和 digest
算法创建的 signature
匹配。
# File rubygems/security/policy.rb, line 75 def check_data(public_key, digest, signature, data) raise Gem::Security::Exception, "invalid signature" unless public_key.verify digest, signature, data.digest true end
check_key(signer, key) 点击切换源代码
确保 key
的公钥与 signer
中的公钥匹配
# File rubygems/security/policy.rb, line 112 def check_key(signer, key) unless signer && key return true unless @only_signed raise Gem::Security::Exception, "missing key or signature" end raise Gem::Security::Exception, "certificate #{signer.subject} does not match the signing key" unless signer.check_private_key(key) true end
check_root(chain, time) 点击切换源代码
确保 chain
中的根证书是自签名且在 time
内有效的。
# File rubygems/security/policy.rb, line 130 def check_root(chain, time) raise Gem::Security::Exception, "missing signing chain" unless chain root = chain.first raise Gem::Security::Exception, "missing root certificate" unless root raise Gem::Security::Exception, "root certificate #{root.subject} is not self-signed " \ "(issuer #{root.issuer})" if root.issuer != root.subject check_cert root, root, time end
check_trust(chain, digester, trust_dir) 点击切换源代码
确保 chain
的根证书在 trust_dir
中具有受信任的证书,并且两个证书的摘要根据 digester
匹配
# File rubygems/security/policy.rb, line 149 def check_trust(chain, digester, trust_dir) raise Gem::Security::Exception, "missing signing chain" unless chain root = chain.first raise Gem::Security::Exception, "missing root certificate" unless root path = Gem::Security.trust_dir.cert_path root unless File.exist? path message = "root cert #{root.subject} is not trusted".dup message << " (root of signing cert #{chain.last.subject})" if chain.length > 1 raise Gem::Security::Exception, message end save_cert = OpenSSL::X509::Certificate.new File.read path save_dgst = digester.digest save_cert.public_key.to_pem pkey_str = root.public_key.to_pem cert_dgst = digester.digest pkey_str raise Gem::Security::Exception, "trusted root certificate #{root.subject} checksum " \ "does not match signing root certificate checksum" unless save_dgst == cert_dgst true end
verify(chain, key = nil, digests = {}, signatures = {}, full_name = "(unknown)") 点击切换源代码
对于 full_name
,验证证书 chain
是否有效,digests
是否与签名者根据 policy
设置创建的签名 signatures
匹配。
如果给定了 key
,则使用它来验证签名证书。
# File rubygems/security/policy.rb, line 206 def verify(chain, key = nil, digests = {}, signatures = {}, full_name = "(unknown)") if signatures.empty? if @only_signed raise Gem::Security::Exception, "unsigned gems are not allowed by the #{name} policy" elsif digests.empty? # lack of signatures is irrelevant if there is nothing to check # against else alert_warning "#{full_name} is not signed" return end end opt = @opt digester = Gem::Security.create_digest trust_dir = opt[:trust_dir] time = Time.now _, signer_digests = digests.find do |_algorithm, file_digests| file_digests.values.first.name == Gem::Security::DIGEST_NAME end if @verify_data raise Gem::Security::Exception, "no digests provided (probable bug)" if signer_digests.nil? || signer_digests.empty? else signer_digests = {} end signer = chain.last check_key signer, key if key check_cert signer, nil, time if @verify_signer check_chain chain, time if @verify_chain check_root chain, time if @verify_root if @only_trusted check_trust chain, digester, trust_dir elsif signatures.empty? && digests.empty? # trust is irrelevant if there's no signatures to verify else alert_warning "#{subject signer} is not trusted for #{full_name}" end signatures.each do |file, _| digest = signer_digests[file] raise Gem::Security::Exception, "missing digest for #{file}" unless digest end signer_digests.each do |file, digest| signature = signatures[file] raise Gem::Security::Exception, "missing signature for #{file}" unless signature check_data signer.public_key, digester, signature, digest if @verify_data end true end
verify_signatures(spec, digests, signatures) 点击切换源代码
从 spec
中提取证书链,并调用 verify
以确保签名和证书链根据策略有效。
# File rubygems/security/policy.rb, line 277 def verify_signatures(spec, digests, signatures) chain = spec.cert_chain.map do |cert_pem| OpenSSL::X509::Certificate.new cert_pem end verify chain, nil, digests, signatures, spec.full_name true end