summaryrefslogtreecommitdiff
path: root/ruby_2_2/lib/rubygems/security
diff options
context:
space:
mode:
Diffstat (limited to 'ruby_2_2/lib/rubygems/security')
-rw-r--r--ruby_2_2/lib/rubygems/security/policies.rb115
-rw-r--r--ruby_2_2/lib/rubygems/security/policy.rb295
-rw-r--r--ruby_2_2/lib/rubygems/security/signer.rb154
-rw-r--r--ruby_2_2/lib/rubygems/security/trust_dir.rb118
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
-