mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 8f0bce5ddc
			
		
	
	
		8f0bce5ddc
		
	
	
	
	
		
			
			git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11094 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			174 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| #!/usr/bin/env ruby
 | |
| 
 | |
| require 'openssl'
 | |
| require 'digest/md5'
 | |
| 
 | |
| class CHashDir
 | |
|   include Enumerable
 | |
| 
 | |
|   def initialize(dirpath)
 | |
|     @dirpath = dirpath
 | |
|     @fingerprint_cache = @cert_cache = @crl_cache = nil
 | |
|   end
 | |
| 
 | |
|   def hash_dir(silent = false)
 | |
|     # ToDo: Should lock the directory...
 | |
|     @silent = silent
 | |
|     @fingerprint_cache = Hash.new
 | |
|     @cert_cache = Hash.new
 | |
|     @crl_cache = Hash.new
 | |
|     do_hash_dir
 | |
|   end
 | |
| 
 | |
|   def get_certs(name = nil)
 | |
|     if name
 | |
|       @cert_cache[hash_name(name)]
 | |
|     else
 | |
|       @cert_cache.values.flatten
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def get_crls(name = nil)
 | |
|     if name
 | |
|       @crl_cache[hash_name(name)]
 | |
|     else
 | |
|       @crl_cache.values.flatten
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def delete_crl(crl)
 | |
|     File.unlink(crl_filename(crl))
 | |
|     hash_dir(true)
 | |
|   end
 | |
| 
 | |
|   def add_crl(crl)
 | |
|     File.open(crl_filename(crl), "w") do |f|
 | |
|       f << crl.to_pem
 | |
|     end
 | |
|     hash_dir(true)
 | |
|   end
 | |
| 
 | |
|   def load_pem_file(filepath)
 | |
|     str = File.read(filepath)
 | |
|     begin
 | |
|       OpenSSL::X509::Certificate.new(str)
 | |
|     rescue
 | |
|       begin
 | |
| 	OpenSSL::X509::CRL.new(str)
 | |
|       rescue
 | |
| 	begin
 | |
| 	  OpenSSL::X509::Request.new(str)
 | |
| 	rescue
 | |
| 	  nil
 | |
| 	end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
| private
 | |
| 
 | |
|   def crl_filename(crl)
 | |
|     path(hash_name(crl.issuer)) + '.pem'
 | |
|   end
 | |
| 
 | |
|   def do_hash_dir
 | |
|     Dir.chdir(@dirpath) do
 | |
|       delete_symlink
 | |
|       Dir.glob('*.pem') do |pemfile|
 | |
| 	cert = load_pem_file(pemfile)
 | |
| 	case cert
 | |
| 	when OpenSSL::X509::Certificate
 | |
| 	  link_hash_cert(pemfile, cert)
 | |
| 	when OpenSSL::X509::CRL
 | |
| 	  link_hash_crl(pemfile, cert)
 | |
| 	else
 | |
| 	  STDERR.puts("WARNING: #{pemfile} does not contain a certificate or CRL: skipping") unless @silent
 | |
| 	end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def delete_symlink
 | |
|     Dir.entries(".").each do |entry|
 | |
|       next unless /^[\da-f]+\.r{0,1}\d+$/ =~ entry
 | |
|       File.unlink(entry) if FileTest.symlink?(entry)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def link_hash_cert(org_filename, cert)
 | |
|     name_hash = hash_name(cert.subject)
 | |
|     fingerprint = fingerprint(cert.to_der)
 | |
|     filepath = link_hash(org_filename, name_hash, fingerprint) { |idx|
 | |
|       "#{name_hash}.#{idx}"
 | |
|     }
 | |
|     unless filepath
 | |
|       unless @silent
 | |
| 	STDERR.puts("WARNING: Skipping duplicate certificate #{org_filename}")
 | |
|       end
 | |
|     else
 | |
|       (@cert_cache[name_hash] ||= []) << path(filepath)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def link_hash_crl(org_filename, crl)
 | |
|     name_hash = hash_name(crl.issuer)
 | |
|     fingerprint = fingerprint(crl.to_der)
 | |
|     filepath = link_hash(org_filename, name_hash, fingerprint) { |idx|
 | |
|       "#{name_hash}.r#{idx}"
 | |
|     }
 | |
|     unless filepath
 | |
|       unless @silent
 | |
| 	STDERR.puts("WARNING: Skipping duplicate CRL #{org_filename}")
 | |
|       end
 | |
|     else
 | |
|       (@crl_cache[name_hash] ||= []) << path(filepath)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def link_hash(org_filename, name, fingerprint)
 | |
|     idx = 0
 | |
|     filepath = nil
 | |
|     while true
 | |
|       filepath = yield(idx)
 | |
|       break unless FileTest.symlink?(filepath) or FileTest.exist?(filepath)
 | |
|       if @fingerprint_cache[filepath] == fingerprint
 | |
| 	return false
 | |
|       end
 | |
|       idx += 1
 | |
|     end
 | |
|     STDOUT.puts("#{org_filename} => #{filepath}") unless @silent
 | |
|     symlink(org_filename, filepath)
 | |
|     @fingerprint_cache[filepath] = fingerprint
 | |
|     filepath
 | |
|   end
 | |
| 
 | |
|   def symlink(from, to)
 | |
|     begin
 | |
|       File.symlink(from, to)
 | |
|     rescue
 | |
|       File.open(to, "w") do |f|
 | |
| 	f << File.read(from)
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def path(filename)
 | |
|     File.join(@dirpath, filename)
 | |
|   end
 | |
| 
 | |
|   def hash_name(name)
 | |
|     sprintf("%x", name.hash)
 | |
|   end
 | |
| 
 | |
|   def fingerprint(der)
 | |
|     Digest::MD5.hexdigest(der).upcase
 | |
|   end
 | |
| end
 | |
| 
 | |
| if $0 == __FILE__
 | |
|   dirlist = ARGV
 | |
|   dirlist << '/usr/ssl/certs' if dirlist.empty?
 | |
|   dirlist.each do |dir|
 | |
|     CHashDir.new(dir).hash_dir
 | |
|   end
 | |
| end
 |