diff options
Diffstat (limited to 'ruby_2_2/lib/rubygems/security')
-rw-r--r-- | ruby_2_2/lib/rubygems/security/policies.rb | 115 | ||||
-rw-r--r-- | ruby_2_2/lib/rubygems/security/policy.rb | 295 | ||||
-rw-r--r-- | ruby_2_2/lib/rubygems/security/signer.rb | 154 | ||||
-rw-r--r-- | ruby_2_2/lib/rubygems/security/trust_dir.rb | 118 |
4 files changed, 0 insertions, 682 deletions
diff --git a/ruby_2_2/lib/rubygems/security/policies.rb b/ruby_2_2/lib/rubygems/security/policies.rb deleted file mode 100644 index a976ecaf59..0000000000 --- a/ruby_2_2/lib/rubygems/security/policies.rb +++ /dev/null @@ -1,115 +0,0 @@ -module Gem::Security - - ## - # No security policy: all package signature checks are disabled. - - NoSecurity = Policy.new( - 'No Security', - :verify_data => false, - :verify_signer => false, - :verify_chain => false, - :verify_root => false, - :only_trusted => false, - :only_signed => false - ) - - ## - # AlmostNo security policy: only verify that the signing certificate is the - # one that actually signed the data. Make no attempt to verify the signing - # certificate chain. - # - # This policy is basically useless. better than nothing, but can still be - # easily spoofed, and is not recommended. - - AlmostNoSecurity = Policy.new( - 'Almost No Security', - :verify_data => true, - :verify_signer => false, - :verify_chain => false, - :verify_root => false, - :only_trusted => false, - :only_signed => false - ) - - ## - # Low security policy: only verify that the signing certificate is actually - # the gem signer, and that the signing certificate is valid. - # - # This policy is better than nothing, but can still be easily spoofed, and - # is not recommended. - - LowSecurity = Policy.new( - 'Low Security', - :verify_data => true, - :verify_signer => true, - :verify_chain => false, - :verify_root => false, - :only_trusted => false, - :only_signed => false - ) - - ## - # Medium security policy: verify the signing certificate, verify the signing - # certificate chain all the way to the root certificate, and only trust root - # certificates that we have explicitly allowed trust for. - # - # This security policy is reasonable, but it allows unsigned packages, so a - # malicious person could simply delete the package signature and pass the - # gem off as unsigned. - - MediumSecurity = Policy.new( - 'Medium Security', - :verify_data => true, - :verify_signer => true, - :verify_chain => true, - :verify_root => true, - :only_trusted => true, - :only_signed => false - ) - - ## - # High security policy: only allow signed gems to be installed, verify the - # signing certificate, verify the signing certificate chain all the way to - # the root certificate, and only trust root certificates that we have - # explicitly allowed trust for. - # - # This security policy is significantly more difficult to bypass, and offers - # a reasonable guarantee that the contents of the gem have not been altered. - - HighSecurity = Policy.new( - 'High Security', - :verify_data => true, - :verify_signer => true, - :verify_chain => true, - :verify_root => true, - :only_trusted => true, - :only_signed => true - ) - - ## - # Policy used to verify a certificate and key when signing a gem - - SigningPolicy = Policy.new( - 'Signing Policy', - :verify_data => false, - :verify_signer => true, - :verify_chain => true, - :verify_root => true, - :only_trusted => false, - :only_signed => false - ) - - ## - # Hash of configured security policies - - Policies = { - 'NoSecurity' => NoSecurity, - 'AlmostNoSecurity' => AlmostNoSecurity, - 'LowSecurity' => LowSecurity, - 'MediumSecurity' => MediumSecurity, - 'HighSecurity' => HighSecurity, - # SigningPolicy is not intended for use by `gem -P` so do not list it - } - -end - diff --git a/ruby_2_2/lib/rubygems/security/policy.rb b/ruby_2_2/lib/rubygems/security/policy.rb deleted file mode 100644 index b9bcb17525..0000000000 --- a/ruby_2_2/lib/rubygems/security/policy.rb +++ /dev/null @@ -1,295 +0,0 @@ -require 'rubygems/user_interaction' - -## -# 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 in -# Gem::Security::Policies. - -class Gem::Security::Policy - - include Gem::UserInteraction - - attr_reader :name - - attr_accessor :only_signed - attr_accessor :only_trusted - attr_accessor :verify_chain - attr_accessor :verify_data - attr_accessor :verify_root - attr_accessor :verify_signer - - ## - # Create a new Gem::Security::Policy object with the given mode and - # options. - - 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 - - ## - # Verifies each certificate in +chain+ has signed the following certificate - # and is valid for the given +time+. - - 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 - - ## - # Verifies that +data+ matches the +signature+ created by +public_key+ and - # the +digest+ algorithm. - - def check_data public_key, digest, signature, data - raise Gem::Security::Exception, "invalid signature" unless - public_key.verify digest.new, signature, data.digest - - true - end - - ## - # Ensures that +signer+ is valid for +time+ and was signed by the +issuer+. - # If the +issuer+ is +nil+ no verification is performed. - - 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 and not_before > time then - raise Gem::Security::Exception, - "#{message} not valid before #{not_before}" - end - - if not_after = signer.not_after and not_after < time then - raise Gem::Security::Exception, "#{message} not valid after #{not_after}" - end - - if issuer and not signer.verify issuer.public_key then - raise Gem::Security::Exception, - "#{message} was not issued by #{issuer.subject}" - end - - true - end - - ## - # Ensures the public key of +key+ matches the public key in +signer+ - - 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 - - ## - # Ensures the root certificate in +chain+ is self-signed and valid for - # +time+. - - 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 - - ## - # Ensures the root of +chain+ has a trusted certificate in +trust_dir+ and - # the digests of the two certificates match according to +digester+ - - 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 - message = "root cert #{root.subject} is not trusted" - - 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_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 - - ## - # Extracts the email or subject from +certificate+ - - def subject certificate # :nodoc: - certificate.extensions.each do |extension| - next unless extension.oid == 'subjectAltName' - - return extension.value - end - - certificate.subject.to_s - end - - 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 - - ## - # 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. - - 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 - - ## - # Extracts the certificate chain from the +spec+ and calls #verify to ensure - # the signatures and certificate chain is valid according to the policy.. - - 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 - - alias to_s name # :nodoc: - -end - diff --git a/ruby_2_2/lib/rubygems/security/signer.rb b/ruby_2_2/lib/rubygems/security/signer.rb deleted file mode 100644 index bb1eae7cf2..0000000000 --- a/ruby_2_2/lib/rubygems/security/signer.rb +++ /dev/null @@ -1,154 +0,0 @@ -## -# Basic OpenSSL-based package signing class. - -class Gem::Security::Signer - - ## - # The chain of certificates for signing including the signing certificate - - attr_accessor :cert_chain - - ## - # The private key for the signing certificate - - attr_accessor :key - - ## - # The digest algorithm used to create the signature - - attr_reader :digest_algorithm - - ## - # The name of the digest algorithm, used to pull digests out of the hash by - # name. - - attr_reader :digest_name # :nodoc: - - ## - # Creates a new signer with an RSA +key+ or path to a key, and a certificate - # +chain+ containing X509 certificates, encoding certificates or paths to - # certificates. - - def initialize key, cert_chain, passphrase = nil - @cert_chain = cert_chain - @key = key - - unless @key then - default_key = File.join Gem.default_key_path - @key = default_key if File.exist? default_key - end - - unless @cert_chain then - default_cert = File.join Gem.default_cert_path - @cert_chain = [default_cert] if File.exist? default_cert - end - - @digest_algorithm = Gem::Security::DIGEST_ALGORITHM - @digest_name = Gem::Security::DIGEST_NAME - - @key = OpenSSL::PKey::RSA.new File.read(@key), passphrase if - @key and not OpenSSL::PKey::RSA === @key - - if @cert_chain then - @cert_chain = @cert_chain.compact.map do |cert| - next cert if OpenSSL::X509::Certificate === cert - - cert = File.read cert if File.exist? cert - - OpenSSL::X509::Certificate.new cert - end - - load_cert_chain - end - end - - ## - # Extracts the full name of +cert+. If the certificate has a subjectAltName - # this value is preferred, otherwise the subject is used. - - def extract_name cert # :nodoc: - subject_alt_name = cert.extensions.find { |e| 'subjectAltName' == e.oid } - - if subject_alt_name then - /\Aemail:/ =~ subject_alt_name.value - - $' || subject_alt_name.value - else - cert.subject - end - end - - ## - # Loads any missing issuers in the cert chain from the trusted certificates. - # - # If the issuer does not exist it is ignored as it will be checked later. - - def load_cert_chain # :nodoc: - return if @cert_chain.empty? - - while @cert_chain.first.issuer.to_s != @cert_chain.first.subject.to_s do - issuer = Gem::Security.trust_dir.issuer_of @cert_chain.first - - break unless issuer # cert chain is verified later - - @cert_chain.unshift issuer - end - end - - ## - # Sign data with given digest algorithm - - def sign data - return unless @key - - if @cert_chain.length == 1 and @cert_chain.last.not_after < Time.now then - re_sign_key - end - - full_name = extract_name @cert_chain.last - - Gem::Security::SigningPolicy.verify @cert_chain, @key, {}, {}, full_name - - @key.sign @digest_algorithm.new, data - end - - ## - # Attempts to re-sign the private key if the signing certificate is expired. - # - # The key will be re-signed if: - # * The expired certificate is self-signed - # * The expired certificate is saved at ~/.gem/gem-public_cert.pem - # * There is no file matching the expiry date at - # ~/.gem/gem-public_cert.pem.expired.%Y%m%d%H%M%S - # - # If the signing certificate can be re-signed the expired certificate will - # be saved as ~/.gem/gem-pubilc_cert.pem.expired.%Y%m%d%H%M%S where the - # expiry time (not after) is used for the timestamp. - - def re_sign_key # :nodoc: - old_cert = @cert_chain.last - - disk_cert_path = File.join Gem.default_cert_path - disk_cert = File.read disk_cert_path rescue nil - disk_key = - File.read File.join(Gem.default_key_path) rescue nil - - if disk_key == @key.to_pem and disk_cert == old_cert.to_pem then - expiry = old_cert.not_after.strftime '%Y%m%d%H%M%S' - old_cert_file = "gem-public_cert.pem.expired.#{expiry}" - old_cert_path = File.join Gem.user_home, ".gem", old_cert_file - - unless File.exist? old_cert_path then - Gem::Security.write old_cert, old_cert_path - - cert = Gem::Security.re_sign old_cert, @key - - Gem::Security.write cert, disk_cert_path - - @cert_chain = [cert] - end - end - end - -end - diff --git a/ruby_2_2/lib/rubygems/security/trust_dir.rb b/ruby_2_2/lib/rubygems/security/trust_dir.rb deleted file mode 100644 index 76ef89af7f..0000000000 --- a/ruby_2_2/lib/rubygems/security/trust_dir.rb +++ /dev/null @@ -1,118 +0,0 @@ -## -# The TrustDir manages the trusted certificates for gem signature -# verification. - -class Gem::Security::TrustDir - - ## - # Default permissions for the trust directory and its contents - - DEFAULT_PERMISSIONS = { - :trust_dir => 0700, - :trusted_cert => 0600, - } - - ## - # The directory where trusted certificates will be stored. - - attr_reader :dir - - ## - # Creates a new TrustDir using +dir+ where the directory and file - # permissions will be checked according to +permissions+ - - def initialize dir, permissions = DEFAULT_PERMISSIONS - @dir = dir - @permissions = permissions - - @digester = Gem::Security::DIGEST_ALGORITHM - end - - ## - # Returns the path to the trusted +certificate+ - - def cert_path certificate - name_path certificate.subject - end - - ## - # Enumerates trusted certificates. - - def each_certificate - return enum_for __method__ unless block_given? - - glob = File.join @dir, '*.pem' - - Dir[glob].each do |certificate_file| - begin - certificate = load_certificate certificate_file - - yield certificate, certificate_file - rescue OpenSSL::X509::CertificateError - next # HACK warn - end - end - end - - ## - # Returns the issuer certificate of the given +certificate+ if it exists in - # the trust directory. - - def issuer_of certificate - path = name_path certificate.issuer - - return unless File.exist? path - - load_certificate path - end - - ## - # Returns the path to the trusted certificate with the given ASN.1 +name+ - - def name_path name - digest = @digester.hexdigest name.to_s - - File.join @dir, "cert-#{digest}.pem" - end - - ## - # Loads the given +certificate_file+ - - def load_certificate certificate_file - pem = File.read certificate_file - - OpenSSL::X509::Certificate.new pem - end - - ## - # Add a certificate to trusted certificate list. - - def trust_cert certificate - verify - - destination = cert_path certificate - - open destination, 'wb', @permissions[:trusted_cert] do |io| - io.write certificate.to_pem - end - end - - ## - # Make sure the trust directory exists. If it does exist, make sure it's - # actually a directory. If not, then create it with the appropriate - # permissions. - - def verify - if File.exist? @dir then - raise Gem::Security::Exception, - "trust directory #{@dir} is not a directory" unless - File.directory? @dir - - FileUtils.chmod 0700, @dir - else - FileUtils.mkdir_p @dir, :mode => @permissions[:trust_dir] - end - end - -end - |