mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			118 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
# frozen_string_literal: true
 | 
						|
##
 | 
						|
# 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,
 | 
						|
  }.freeze
 | 
						|
 | 
						|
  ##
 | 
						|
  # 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.create_digest
 | 
						|
  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
 | 
						|
 | 
						|
    File.open destination, 'wb', 0600 do |io|
 | 
						|
      io.write certificate.to_pem
 | 
						|
      io.chmod(@permissions[:trusted_cert])
 | 
						|
    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
 | 
						|
    require 'fileutils'
 | 
						|
    if File.exist? @dir
 | 
						|
      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
 |