Class: Gem::Security::Policy
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
|
|
Inherits: | Object |
Defined in: | lib/rubygems/security/policy.rb, lib/rubygems/security_option.rb, lib/rubygems/commands/unpack_command.rb |
Overview
A 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 in Policies.
Class Method Summary
-
.new(name, policy = {}, opt = {}) ⇒ Policy
constructor
Create a new
Policy
object with the given mode and options.
Instance Attribute Summary
- #name (also: #to_s) readonly
- #only_signed rw
- #only_trusted rw
- #verify_chain rw
- #verify_data rw
- #verify_root rw
- #verify_signer rw
-
#to_s
readonly
Internal use only
Alias for #name.
::Gem::DefaultUserInteraction - Included
Instance Method Summary
-
#check_cert(signer, issuer, time)
Ensures that
signer
is valid for Gem.time and was signed by theissuer
. -
#check_chain(chain, time)
Verifies each certificate in
chain
has signed the following certificate and is valid for the given Gem.time. -
#check_data(public_key, digest, signature, data)
Verifies that
data
matches thesignature
created bypublic_key
and thedigest
algorithm. -
#check_key(signer, key)
Ensures the public key of
key
matches the public key insigner
-
#check_root(chain, time)
Ensures the root certificate in
chain
is self-signed and valid for Gem.time. -
#check_trust(chain, digester, trust_dir)
Ensures the root of
chain
has a trusted certificate in trust_dir and the digests of the two certificates match according todigester
-
#verify(chain, key = nil, digests = {}, signatures = {}, full_name = '(unknown)')
For
full_name
, verifies the certificatechain
is valid, thedigests
match the signaturessignatures
created by the signer depending on thepolicy
settings. -
#verify_signatures(spec, digests, signatures)
Extracts the certificate chain from the
spec
and calls #verify to ensure the signatures and certificate chain is valid according to the policy.. - #inspect Internal use only
-
#subject(certificate)
Internal use only
Extracts the email or subject from
certificate
::Gem::UserInteraction - Included
#alert | Displays an alert |
#alert_error | Displays an error |
#alert_warning | Displays a warning |
#ask | Asks a |
#ask_for_password | Asks for a password with a |
#ask_yes_no | Asks a yes or no |
#choose_from_list | Asks the user to answer |
#say | Displays the given |
#terminate_interaction | Terminates the RubyGems process with the given |
#verbose | Calls |
::Gem::DefaultUserInteraction - Included
::Gem::Text - Included
#clean_text | Remove any non-printable characters and make the text suitable for printing. |
#format_text | Wraps |
#levenshtein_distance | This code is based directly on the ::Gem::Text gem implementation Returns a value representing the “cost” of transforming str1 into str2. |
#truncate_text, #min3 |
Constructor Details
.new(name, policy = {}, opt = {}) ⇒ Policy
Create a new Policy
object with the given mode and options.
# File 'lib/rubygems/security/policy.rb', line 27
def initialize name, policy = {}, opt = {} require 'openssl' @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
Instance Attribute Details
#name (readonly) Also known as: #to_s
[ GitHub ]# File 'lib/rubygems/security/policy.rb', line 14
attr_reader :name
#only_signed (rw)
[ GitHub ]# File 'lib/rubygems/security/policy.rb', line 16
attr_accessor :only_signed
#only_trusted (rw)
[ GitHub ]# File 'lib/rubygems/security/policy.rb', line 17
attr_accessor :only_trusted
#to_s (readonly)
Alias for #name.
# File 'lib/rubygems/security/policy.rb', line 293
alias to_s name # :nodoc:
#verify_chain (rw)
[ GitHub ]# File 'lib/rubygems/security/policy.rb', line 18
attr_accessor :verify_chain
#verify_data (rw)
[ GitHub ]# File 'lib/rubygems/security/policy.rb', line 19
attr_accessor :verify_data
#verify_root (rw)
[ GitHub ]# File 'lib/rubygems/security/policy.rb', line 20
attr_accessor :verify_root
#verify_signer (rw)
[ GitHub ]# File 'lib/rubygems/security/policy.rb', line 21
attr_accessor :verify_signer
Instance Method Details
#check_cert(signer, issuer, time)
Ensures that signer
is valid for Gem.time and was signed by the issuer
. If the issuer
is nil
no verification is performed.
# File 'lib/rubygems/security/policy.rb', line 88
def check_cert signer, issuer, time raise Gem::Security::Exception, 'missing signing certificate' unless signer = "certificate #{signer.subject}" if not_before = signer.not_before and not_before > time then raise Gem::Security::Exception, "#{} not valid before #{not_before}" end if not_after = signer.not_after and not_after < time then raise Gem::Security::Exception, "#{} not valid after #{not_after}" end if issuer and not signer.verify issuer.public_key then raise Gem::Security::Exception, "#{} was not issued by #{issuer.subject}" end true end
#check_chain(chain, time)
Verifies each certificate in chain
has signed the following certificate and is valid for the given Gem.time.
# File 'lib/rubygems/security/policy.rb', line 58
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.}" end end
#check_data(public_key, digest, signature, data)
Verifies that data
matches the signature
created by public_key
and the digest
algorithm.
#check_key(signer, key)
Ensures the public key of key
matches the public key in signer
# File 'lib/rubygems/security/policy.rb', line 114
def check_key signer, key unless signer and key then 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.public_key.to_pem == key.public_key.to_pem true end
#check_root(chain, time)
Ensures the root certificate in chain
is self-signed and valid for Gem.time.
# File 'lib/rubygems/security/policy.rb', line 132
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.to_s != root.subject.to_s # HACK to_s is for ruby 1.8 check_cert root, root, time end
#check_trust(chain, digester, trust_dir)
Ensures the root of chain
has a trusted certificate in Gem::Security.trust_dir and the digests of the two certificates match according to digester
# File 'lib/rubygems/security/policy.rb', line 151
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 then = "root cert #{root.subject} is not trusted".dup << " (root of signing cert #{chain.last.subject})" if chain.length > 1 raise Gem::Security::Exception, end save_cert = OpenSSL::X509::Certificate.new File.read path save_dgst = digester.digest save_cert.public_key.to_s pkey_str = root.public_key.to_s 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
#inspect
# File 'lib/rubygems/security/policy.rb', line 196
def inspect # :nodoc: ("[Policy: %s - data: %p signer: %p chain: %p root: %p " + "signed-only: %p trusted-only: %p]") % [ @name, @verify_chain, @verify_data, @verify_root, @verify_signer, @only_signed, @only_trusted, ] end
#subject(certificate)
Extracts the email or subject from certificate
# File 'lib/rubygems/security/policy.rb', line 186
def subject certificate # :nodoc: certificate.extensions.each do |extension| next unless extension.oid == 'subjectAltName' return extension.value end certificate.subject.to_s end
#verify(chain, key = nil, digests = {}, signatures = {}, full_name = '(unknown)')
For full_name
, verifies the certificate chain
is valid, the digests
match the signatures signatures
created by the signer depending on the policy
settings.
If key
is given it is used to validate the signing certificate.
# File 'lib/rubygems/security/policy.rb', line 211
def verify chain, key = nil, digests = {}, signatures = {}, full_name = '(unknown)' if signatures.empty? then if @only_signed then raise Gem::Security::Exception, "unsigned gems are not allowed by the #{name} policy" elsif digests.empty? then # 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::DIGEST_ALGORITHM 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 then raise Gem::Security::Exception, 'no digests provided (probable bug)' if signer_digests.nil? or 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 then check_trust chain, digester, trust_dir elsif signatures.empty? and digests.empty? then # 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)
Extracts the certificate chain from the spec
and calls #verify to ensure the signatures and certificate chain is valid according to the policy..