summaryrefslogtreecommitdiff
path: root/sample/openssl
diff options
context:
space:
mode:
Diffstat (limited to 'sample/openssl')
-rw-r--r--sample/openssl/c_rehash.rb174
-rw-r--r--sample/openssl/cert2text.rb23
-rw-r--r--sample/openssl/cert_store_view.rb911
-rw-r--r--sample/openssl/certstore.rb161
-rw-r--r--sample/openssl/cipher.rb29
-rw-r--r--sample/openssl/crlstore.rb122
-rw-r--r--sample/openssl/echo_cli.rb37
-rw-r--r--sample/openssl/echo_svr.rb62
-rw-r--r--sample/openssl/gen_csr.rb52
-rw-r--r--sample/openssl/smime_read.rb23
-rw-r--r--sample/openssl/smime_write.rb23
-rw-r--r--sample/openssl/wget.rb33
12 files changed, 1650 insertions, 0 deletions
diff --git a/sample/openssl/c_rehash.rb b/sample/openssl/c_rehash.rb
new file mode 100644
index 00000000000..386eef5f24e
--- /dev/null
+++ b/sample/openssl/c_rehash.rb
@@ -0,0 +1,174 @@
+#!/usr/bin/env ruby
+
+require 'openssl'
+require '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)
+ 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
diff --git a/sample/openssl/cert2text.rb b/sample/openssl/cert2text.rb
new file mode 100644
index 00000000000..50da224e767
--- /dev/null
+++ b/sample/openssl/cert2text.rb
@@ -0,0 +1,23 @@
+#!/usr/bin/env ruby
+
+require 'openssl'
+include OpenSSL::X509
+
+def cert2text(cert_str)
+ [Certificate, CRL, Request].each do |klass|
+ begin
+ puts klass.new(cert_str).to_text
+ return
+ rescue
+ end
+ end
+ raise ArgumentError.new('Unknown format.')
+end
+
+if ARGV.empty?
+ cert2text(STDIN.read)
+else
+ ARGV.each do |file|
+ cert2text(File.read(file))
+ end
+end
diff --git a/sample/openssl/cert_store_view.rb b/sample/openssl/cert_store_view.rb
new file mode 100644
index 00000000000..26c4d527f76
--- /dev/null
+++ b/sample/openssl/cert_store_view.rb
@@ -0,0 +1,911 @@
+#!/usr/bin/env ruby
+
+require 'fox'
+require 'openssl'
+require 'time'
+require 'certstore'
+require 'getopts'
+
+include Fox
+
+module CertDumpSupport
+ def cert_label(cert)
+ subject_alt_name =
+ cert.extensions.find { |ext| ext.oid == 'subjectAltName' }
+ if subject_alt_name
+ subject_alt_name.value.split(/\s*,\s/).each do |alt_name_pair|
+ alt_tag, alt_name = alt_name_pair.split(/:/)
+ return alt_name
+ end
+ end
+ name_label(cert.subject)
+ end
+
+ def name_label(name)
+ ary = name.to_a
+ if (cn = ary.find { |rdn| rdn[0] == 'CN' })
+ return cn[1]
+ end
+ if ary.last[0] == 'OU'
+ return ary.last[1]
+ end
+ name.to_s
+ end
+
+ def name_text(name)
+ name.to_a.collect { |tag, value|
+ "#{tag} = #{value}"
+ }.reverse.join("\n")
+ end
+
+ def bn_label(bn)
+ ("0" << sprintf("%X", bn)).scan(/../).join(" ")
+ end
+end
+
+class CertDump
+ include CertDumpSupport
+
+ def initialize(cert)
+ @cert = cert
+ end
+
+ def get_dump(tag)
+ case tag
+ when 'Version'
+ version
+ when 'Serial'
+ serial
+ when 'Signature Algorithm'
+ signature_algorithm
+ when 'Issuer'
+ issuer
+ when 'Validity'
+ validity
+ when 'Not before'
+ not_before
+ when 'Not after'
+ not_after
+ when 'Subject'
+ subject
+ when 'Public key'
+ public_key
+ else
+ ext(tag)
+ end
+ end
+
+ def get_dump_line(tag)
+ case tag
+ when 'Version'
+ version_line
+ when 'Serial'
+ serial_line
+ when 'Signature Algorithm'
+ signature_algorithm_line
+ when 'Subject'
+ subject_line
+ when 'Issuer'
+ issuer_line
+ when 'Validity'
+ validity_line
+ when 'Not before'
+ not_before_line
+ when 'Not after'
+ not_after_line
+ when 'Public key'
+ public_key_line
+ else
+ ext_line(tag)
+ end
+ end
+
+private
+
+ def version
+ "Version: #{@cert.version + 1}"
+ end
+
+ def version_line
+ version
+ end
+
+ def serial
+ bn_label(@cert.serial)
+ end
+
+ def serial_line
+ serial
+ end
+
+ def signature_algorithm
+ @cert.signature_algorithm
+ end
+
+ def signature_algorithm_line
+ signature_algorithm
+ end
+
+ def subject
+ name_text(@cert.subject)
+ end
+
+ def subject_line
+ @cert.subject.to_s
+ end
+
+ def issuer
+ name_text(@cert.issuer)
+ end
+
+ def issuer_line
+ @cert.issuer.to_s
+ end
+
+ def validity
+ <<EOS
+Not before: #{not_before}
+Not after: #{not_after}
+EOS
+ end
+
+ def validity_line
+ "from #{@cert.not_before.iso8601} to #{@cert.not_after.iso8601}"
+ end
+
+ def not_before
+ @cert.not_before.to_s
+ end
+
+ def not_before_line
+ not_before
+ end
+
+ def not_after
+ @cert.not_after.to_s
+ end
+
+ def not_after_line
+ not_after
+ end
+
+ def public_key
+ @cert.public_key.to_text
+ end
+
+ def public_key_line
+ "#{@cert.public_key.class} -- " << public_key.scan(/\A[^\n]*/)[0] << '...'
+ end
+
+ def ext(tag)
+ @cert.extensions.each do |ext|
+ if ext.oid == tag
+ return ext_detail(tag, ext.value)
+ end
+ end
+ "(unknown)"
+ end
+
+ def ext_line(tag)
+ ext(tag).tr("\r\n", '')
+ end
+
+ def ext_detail(tag, value)
+ value
+ end
+end
+
+class CrlDump
+ include CertDumpSupport
+
+ def initialize(crl)
+ @crl = crl
+ end
+
+ def get_dump(tag)
+ case tag
+ when 'Version'
+ version
+ when 'Signature Algorithm'
+ signature_algorithm
+ when 'Issuer'
+ issuer
+ when 'Last update'
+ last_update
+ when 'Next update'
+ next_update
+ else
+ ext(tag)
+ end
+ end
+
+ def get_dump_line(tag)
+ case tag
+ when 'Version'
+ version_line
+ when 'Signature Algorithm'
+ signature_algorithm_line
+ when 'Issuer'
+ issuer_line
+ when 'Last update'
+ last_update_line
+ when 'Next update'
+ next_update_line
+ else
+ ext_line(tag)
+ end
+ end
+
+private
+
+ def version
+ "Version: #{@crl.version + 1}"
+ end
+
+ def version_line
+ version
+ end
+
+ def signature_algorithm
+ @crl.signature_algorithm
+ end
+
+ def signature_algorithm_line
+ signature_algorithm
+ end
+
+ def issuer
+ name_text(@crl.issuer)
+ end
+
+ def issuer_line
+ @crl.issuer.to_s
+ end
+
+ def last_update
+ @crl.last_update.to_s
+ end
+
+ def last_update_line
+ last_update
+ end
+
+ def next_update
+ @crl.next_update.to_s
+ end
+
+ def next_update_line
+ next_update
+ end
+
+ def ext(tag)
+ @crl.extensions.each do |ext|
+ if ext.oid == tag
+ return ext_detail(tag, ext.value)
+ end
+ end
+ "(unknown)"
+ end
+
+ def ext_line(tag)
+ ext(tag).tr("\r\n", '')
+ end
+
+ def ext_detail(tag, value)
+ value
+ end
+end
+
+class RevokedDump
+ include CertDumpSupport
+
+ def initialize(revoked)
+ @revoked = revoked
+ end
+
+ def get_dump(tag)
+ case tag
+ when 'Serial'
+ serial
+ when 'Time'
+ time
+ else
+ ext(tag)
+ end
+ end
+
+ def get_dump_line(tag)
+ case tag
+ when 'Serial'
+ serial_line
+ when 'Time'
+ time_line
+ else
+ ext_line(tag)
+ end
+ end
+
+private
+
+ def serial
+ bn_label(@revoked.serial)
+ end
+
+ def serial_line
+ serial
+ end
+
+ def time
+ @revoked.time.to_s
+ end
+
+ def time_line
+ time
+ end
+
+ def ext(tag)
+ @revoked.extensions.each do |ext|
+ if ext.oid == tag
+ return ext_detail(tag, ext.value)
+ end
+ end
+ "(unknown)"
+ end
+
+ def ext_line(tag)
+ ext(tag).tr("\r\n", '')
+ end
+
+ def ext_detail(tag, value)
+ value
+ end
+end
+
+class RequestDump
+ include CertDumpSupport
+
+ def initialize(req)
+ @req = req
+ end
+
+ def get_dump(tag)
+ case tag
+ when 'Version'
+ version
+ when 'Signature Algorithm'
+ signature_algorithm
+ when 'Subject'
+ subject
+ when 'Public key'
+ public_key
+ else
+ attributes(tag)
+ end
+ end
+
+ def get_dump_line(tag)
+ case tag
+ when 'Version'
+ version_line
+ when 'Signature Algorithm'
+ signature_algorithm_line
+ when 'Subject'
+ subject_line
+ when 'Public key'
+ public_key_line
+ else
+ attributes_line(tag)
+ end
+ end
+
+private
+
+ def version
+ "Version: #{@req.version + 1}"
+ end
+
+ def version_line
+ version
+ end
+
+ def signature_algorithm
+ @req.signature_algorithm
+ end
+
+ def signature_algorithm_line
+ signature_algorithm
+ end
+
+ def subject
+ name_text(@req.subject)
+ end
+
+ def subject_line
+ @req.subject.to_s
+ end
+
+ def public_key
+ @req.public_key.to_text
+ end
+
+ def public_key_line
+ "#{@req.public_key.class} -- " << public_key.scan(/\A[^\n]*/)[0] << '...'
+ end
+
+ def attributes(tag)
+ "(unknown)"
+ end
+
+ def attributes_line(tag)
+ attributes(tag).tr("\r\n", '')
+ end
+end
+
+class CertStoreView < FXMainWindow
+ class CertTree
+ include CertDumpSupport
+
+ def initialize(observer, tree)
+ @observer = observer
+ @tree = tree
+ @tree.connect(SEL_COMMAND) do |sender, sel, item|
+ if item.data
+ @observer.getApp().beginWaitCursor do
+ @observer.show_item(item.data)
+ end
+ else
+ @observer.show_item(nil)
+ end
+ end
+ end
+
+ def show(cert_store)
+ @tree.clearItems
+ @self_signed_ca_node = add_item_last(nil, "Trusted root CA")
+ @other_ca_node = add_item_last(nil, "Intermediate CA")
+ @ee_node = add_item_last(nil, "Personal")
+ @crl_node = add_item_last(nil, "CRL")
+ @request_node = add_item_last(nil, "Request")
+ @verify_path_node = add_item_last(nil, "Certification path")
+ show_certs(cert_store)
+ end
+
+ def show_certs(cert_store)
+ remove_items(@self_signed_ca_node)
+ remove_items(@other_ca_node)
+ remove_items(@ee_node)
+ remove_items(@crl_node)
+ remove_items(@request_node)
+ import_certs(cert_store)
+ end
+
+ def show_request(req)
+ node = add_item_last(@request_node, name_label(req.subject), req)
+ @tree.selectItem(node)
+ @observer.show_item(req)
+ end
+
+ def show_verify_path(verify_path)
+ add_verify_path(verify_path)
+ end
+
+ private
+
+ def open_node(node)
+ node.expanded = node.opened = true
+ end
+
+ def close_node(node)
+ node.expanded = node.opened = false
+ end
+
+ def import_certs(cert_store)
+ cert_store.self_signed_ca.each do |cert|
+ add_item_last(@self_signed_ca_node, cert_label(cert), cert)
+ end
+ cert_store.other_ca.each do |cert|
+ add_item_last(@other_ca_node, cert_label(cert), cert)
+ end
+ cert_store.ee.each do |cert|
+ add_item_last(@ee_node, cert_label(cert), cert)
+ end
+ cert_store.crl.each do |crl|
+ node = add_item_last(@crl_node, name_label(crl.issuer), crl)
+ close_node(node)
+ crl.revoked.each do |revoked|
+ add_item_last(node, bn_label(revoked.serial), revoked)
+ end
+ end
+ cert_store.request.each do |req|
+ add_item_last(@requestnode, name_label(req.subject), req)
+ end
+ end
+
+ def add_verify_path(verify_path)
+ node = @verify_path_node
+ last_cert = nil
+ verify_path.reverse_each do |ok, cert, crl_check, error_string|
+ warn = []
+ if @observer.cert_store.is_ca?(cert)
+ warn << 'NO ARL' unless crl_check
+ else
+ warn << 'NO CRL' unless crl_check
+ end
+ warn_str = '(' << warn.join(", ") << ')'
+ warn_mark = warn.empty? ? '' : '!'
+ label = if ok
+ "OK#{warn_mark}..." + cert_label(cert)
+ else
+ "NG(#{error_string})..." + cert_label(cert)
+ end
+ label << warn_str unless warn.empty?
+ node = add_item_last(node, label, cert)
+ node.expanded = true
+ last_cert = cert
+ end
+ if last_cert
+ @tree.selectItem(node)
+ @observer.show_item(last_cert)
+ end
+ end
+
+ def add_item_last(parent, label, obj = nil)
+ node = @tree.addItemLast(parent, FXTreeItem.new(label))
+ node.data = obj if obj
+ open_node(node)
+ node
+ end
+
+ def remove_items(node)
+ while node.getNumChildren > 0
+ @tree.removeItem(node.getFirst)
+ end
+ end
+ end
+
+ class CertInfo
+ def initialize(observer, table)
+ @observer = observer
+ @table = table
+ @table.leadingRows = 0
+ @table.leadingCols = 0
+ @table.trailingRows = 0
+ @table.trailingCols = 0
+ @table.showVertGrid(false)
+ @table.showHorzGrid(false)
+ @table.setTableSize(1, 2)
+ @table.setColumnWidth(0, 125)
+ @table.setColumnWidth(1, 350)
+ end
+
+ def show(item)
+ @observer.show_detail(nil, nil)
+ if item.nil?
+ set_column_size(1)
+ return
+ end
+ case item
+ when OpenSSL::X509::Certificate
+ show_cert(item)
+ when OpenSSL::X509::CRL
+ show_crl(item)
+ when OpenSSL::X509::Revoked
+ show_revoked(item)
+ when OpenSSL::X509::Request
+ show_request(item)
+ else
+ raise NotImplementedError.new("Unknown item type #{item.class}.")
+ end
+ end
+
+ private
+
+ def show_cert(cert)
+ wrap = CertDump.new(cert)
+ items = []
+ items << ['Version', wrap.get_dump_line('Version')]
+ items << ['Signature Algorithm', wrap.get_dump_line('Signature Algorithm')]
+ items << ['Issuer', wrap.get_dump_line('Issuer')]
+ items << ['Serial', wrap.get_dump_line('Serial')]
+ #items << ['Not before', wrap.get_dump_line('Not before')]
+ #items << ['Not after', wrap.get_dump_line('Not after')]
+ items << ['Subject', wrap.get_dump_line('Subject')]
+ items << ['Public key', wrap.get_dump_line('Public key')]
+ items << ['Validity', wrap.get_dump_line('Validity')]
+ (cert.extensions.sort { |a, b| a.oid <=> b.oid }).each do |ext|
+ items << [ext.oid, wrap.get_dump_line(ext.oid)]
+ end
+ show_items(cert, items)
+ end
+
+ def show_crl(crl)
+ wrap = CrlDump.new(crl)
+ items = []
+ items << ['Version', wrap.get_dump_line('Version')]
+ items << ['Signature Algorithm', wrap.get_dump_line('Signature Algorithm')]
+ items << ['Issuer', wrap.get_dump_line('Issuer')]
+ items << ['Last update', wrap.get_dump_line('Last update')]
+ items << ['Next update', wrap.get_dump_line('Next update')]
+ crl.extensions.each do |ext|
+ items << [ext.oid, wrap.get_dump_line(ext.oid)]
+ end
+ show_items(crl, items)
+ end
+
+ def show_revoked(revoked)
+ wrap = RevokedDump.new(revoked)
+ items = []
+ items << ['Serial', wrap.get_dump_line('Serial')]
+ items << ['Time', wrap.get_dump_line('Time')]
+ revoked.extensions.each do |ext|
+ items << [ext.oid, wrap.get_dump_line(ext.oid)]
+ end
+ show_items(revoked, items)
+ end
+
+ def show_request(req)
+ wrap = RequestDump.new(req)
+ items = []
+ items << ['Version', wrap.get_dump_line('Version')]
+ items << ['Signature Algorithm', wrap.get_dump_line('Signature Algorithm')]
+ items << ['Subject', wrap.get_dump_line('Subject')]
+ items << ['Public key', wrap.get_dump_line('Public key')]
+ req.attributes.each do |attr|
+ items << [attr.attr, wrap.get_dump_line(attr.oid)]
+ end
+ show_items(req, items)
+ end
+
+ def show_items(obj, items)
+ set_column_size(items.size)
+ items.each_with_index do |ele, idx|
+ tag, value = ele
+ @table.setItemText(idx, 0, tag)
+ @table.getItem(idx, 0).data = tag
+ @table.setItemText(idx, 1, value.to_s)
+ @table.getItem(idx, 1).data = tag
+ end
+ @table.connect(SEL_COMMAND) do |sender, sel, loc|
+ item = @table.getItem(loc.row, loc.col)
+ @observer.show_detail(obj, item.data)
+ end
+ justify_table
+ end
+
+ def set_column_size(size)
+ col0_width = @table.getColumnWidth(0)
+ col1_width = @table.getColumnWidth(1)
+ @table.setTableSize(size, 2)
+ @table.setColumnWidth(0, col0_width)
+ @table.setColumnWidth(1, col1_width)
+ end
+
+ def justify_table
+ for col in 0..@table.numCols-1
+ for row in 0..@table.numRows-1
+ @table.getItem(row, col).justify = FXTableItem::LEFT
+ end
+ end
+ end
+ end
+
+ class CertDetail
+ def initialize(observer, detail)
+ @observer = observer
+ @detail = detail
+ end
+
+ def show(item, tag)
+ if item.nil?
+ @detail.text = ''
+ return
+ end
+ case item
+ when OpenSSL::X509::Certificate
+ show_cert(item, tag)
+ when OpenSSL::X509::CRL
+ show_crl(item, tag)
+ when OpenSSL::X509::Revoked
+ show_revoked(item, tag)
+ when OpenSSL::X509::Request
+ show_request(item, tag)
+ else
+ raise NotImplementedError.new("Unknown item type #{item.class}.")
+ end
+ end
+
+ private
+
+ def show_cert(cert, tag)
+ wrap = CertDump.new(cert)
+ @detail.text = wrap.get_dump(tag)
+ end
+
+ def show_crl(crl, tag)
+ wrap = CrlDump.new(crl)
+ @detail.text = wrap.get_dump(tag)
+ end
+
+ def show_revoked(revoked, tag)
+ wrap = RevokedDump.new(revoked)
+ @detail.text = wrap.get_dump(tag)
+ end
+
+ def show_request(request, tag)
+ wrap = RequestDump.new(request)
+ @detail.text = wrap.get_dump(tag)
+ end
+ end
+
+ attr_reader :cert_store
+
+ def initialize(app, cert_store)
+ @cert_store = cert_store
+ @verify_filter = 0
+ @verify_filename = nil
+ full_width = 800
+ full_height = 500
+ horz_pos = 300
+
+ super(app, "Certificate store", nil, nil, DECOR_ALL, 0, 0, full_width,
+ full_height)
+
+ FXTooltip.new(self.getApp())
+
+ menubar = FXMenubar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
+ file_menu = FXMenuPane.new(self)
+ FXMenuTitle.new(menubar, "&File", nil, file_menu)
+ file_open_menu = FXMenuPane.new(self)
+ FXMenuCommand.new(file_open_menu, "&Directory\tCtl-O").connect(SEL_COMMAND,
+ method(:on_cmd_file_open_dir))
+ FXMenuCascade.new(file_menu, "&Open\tCtl-O", nil, file_open_menu)
+ FXMenuCommand.new(file_menu, "&Quit\tCtl-Q", nil, getApp(), FXApp::ID_QUIT)
+
+ tool_menu = FXMenuPane.new(self)
+ FXMenuTitle.new(menubar, "&Tool", nil, tool_menu)
+ FXMenuCommand.new(tool_menu, "&Verify\tCtl-N").connect(SEL_COMMAND,
+ method(:on_cmd_tool_verify))
+ FXMenuCommand.new(tool_menu, "&Show Request\tCtl-R").connect(SEL_COMMAND,
+ method(:on_cmd_tool_request))
+
+ base_frame = FXHorizontalFrame.new(self, LAYOUT_FILL_X | LAYOUT_FILL_Y)
+ splitter_horz = FXSplitter.new(base_frame, LAYOUT_SIDE_TOP | LAYOUT_FILL_X |
+ LAYOUT_FILL_Y | SPLITTER_TRACKING | SPLITTER_HORIZONTAL)
+
+ # Cert tree
+ cert_tree_frame = FXHorizontalFrame.new(splitter_horz, LAYOUT_FILL_X |
+ LAYOUT_FILL_Y | FRAME_SUNKEN | FRAME_THICK)
+ cert_tree_frame.setWidth(horz_pos)
+ cert_tree = FXTreeList.new(cert_tree_frame, 0, nil, 0,
+ TREELIST_BROWSESELECT | TREELIST_SHOWS_LINES | TREELIST_SHOWS_BOXES |
+ TREELIST_ROOT_BOXES | LAYOUT_FILL_X | LAYOUT_FILL_Y)
+ @cert_tree = CertTree.new(self, cert_tree)
+
+ # Cert info
+ splitter_vert = FXSplitter.new(splitter_horz, LAYOUT_SIDE_TOP |
+ LAYOUT_FILL_X | LAYOUT_FILL_Y | SPLITTER_TRACKING | SPLITTER_VERTICAL |
+ SPLITTER_REVERSED)
+ cert_list_base = FXVerticalFrame.new(splitter_vert, LAYOUT_FILL_X |
+ LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0)
+ cert_list_frame = FXHorizontalFrame.new(cert_list_base, FRAME_SUNKEN |
+ FRAME_THICK | LAYOUT_FILL_X | LAYOUT_FILL_Y)
+ cert_info = FXTable.new(cert_list_frame, 2, 10, nil, 0, FRAME_SUNKEN |
+ TABLE_COL_SIZABLE | LAYOUT_FILL_X | LAYOUT_FILL_Y, 0, 0, 0, 0, 2, 2, 2, 2)
+ @cert_info = CertInfo.new(self, cert_info)
+
+ cert_detail_base = FXVerticalFrame.new(splitter_vert, LAYOUT_FILL_X |
+ LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0)
+ cert_detail_frame = FXHorizontalFrame.new(cert_detail_base, FRAME_SUNKEN |
+ FRAME_THICK | LAYOUT_FILL_X | LAYOUT_FILL_Y)
+ cert_detail = FXText.new(cert_detail_frame, nil, 0, TEXT_READONLY |
+ LAYOUT_FILL_X | LAYOUT_FILL_Y)
+ @cert_detail = CertDetail.new(self, cert_detail)
+
+ show_init
+ end
+
+ def create
+ super
+ show(PLACEMENT_SCREEN)
+ end
+
+ def show_init
+ @cert_tree.show(@cert_store)
+ show_item(nil)
+ end
+
+ def show_certs
+ @cert_tree.show_certs(@cert_store)
+ end
+
+ def show_request(req)
+ @cert_tree.show_request(req)
+ end
+
+ def show_verify_path(verify_path)
+ @cert_tree.show_verify_path(verify_path)
+ end
+
+ def show_item(item)
+ @cert_info.show(item) if @cert_info
+ end
+
+ def show_detail(item, tag)
+ @cert_detail.show(item, tag) if @cert_detail
+ end
+
+ def verify(certfile)
+ path = verify_certfile(certfile)
+ show_certs # CRL could be change.
+ show_verify_path(path)
+ end
+
+private
+
+ def on_cmd_file_open_dir(sender, sel, ptr)
+ dir = FXFileDialog.getOpenDirectory(self, "Open certificate directory", ".")
+ unless dir.empty?
+ begin
+ @cert_store = CertStore.new(dir)
+ rescue
+ show_error($!)
+ end
+ show_init
+ end
+ 1
+ end
+
+ def on_cmd_tool_verify(sender, sel, ptr)
+ dialog = FXFileDialog.new(self, "Verify certificate")
+ dialog.filename = ''
+ dialog.patternList = ["All Files (*)", "PEM formatted certificate (*.pem)"]
+ dialog.currentPattern = @verify_filter
+ if dialog.execute != 0
+ @verify_filename = dialog.filename
+ verify(@verify_filename)
+ end
+ @verify_filter = dialog.currentPattern
+ 1
+ end
+
+ def on_cmd_tool_request(sender, sel, ptr)
+ dialog = FXFileDialog.new(self, "Show request")
+ dialog.filename = ''
+ dialog.patternList = ["All Files (*)", "PEM formatted certificate (*.pem)"]
+ if dialog.execute != 0
+ req = @cert_store.generate_cert(dialog.filename)
+ show_request(req)
+ end
+ 1
+ end
+
+ def verify_certfile(filename)
+ begin
+ cert = @cert_store.generate_cert(filename)
+ result = @cert_store.verify(cert)
+ @cert_store.scan_certs
+ result
+ rescue
+ show_error($!)
+ []
+ end
+ end
+
+ def show_error(e)
+ msg = e.inspect + "\n" + e.backtrace.join("\n")
+ FXMessageBox.error(self, MBOX_OK, "Error", msg)
+ end
+end
+
+getopts nil, "cert:"
+
+certs_dir = ARGV.shift or raise "#{$0} cert_dir"
+certfile = $OPT_cert
+app = FXApp.new("CertStore", "FoxTest")
+cert_store = CertStore.new(certs_dir)
+w = CertStoreView.new(app, cert_store)
+app.create
+if certfile
+ w.verify(certfile)
+end
+app.run
diff --git a/sample/openssl/certstore.rb b/sample/openssl/certstore.rb
new file mode 100644
index 00000000000..bbc637f6683
--- /dev/null
+++ b/sample/openssl/certstore.rb
@@ -0,0 +1,161 @@
+require 'c_rehash'
+require 'crlstore'
+
+
+class CertStore
+ include OpenSSL
+ include X509
+
+ attr_reader :self_signed_ca
+ attr_reader :other_ca
+ attr_reader :ee
+ attr_reader :crl
+ attr_reader :request
+
+ def initialize(certs_dir)
+ @certs_dir = certs_dir
+ @c_store = CHashDir.new(@certs_dir)
+ @c_store.hash_dir(true)
+ @crl_store = CrlStore.new(@c_store)
+ @x509store = Store.new
+ @self_signed_ca = @other_ca = @ee = @crl = nil
+
+ # Uncomment this line to let OpenSSL to check CRL for each certs.
+ # @x509store.flags = V_FLAG_CRL_CHECK | V_FLAG_CRL_CHECK_ALL
+
+ add_path
+ scan_certs
+ end
+
+ def generate_cert(filename)
+ @c_store.load_pem_file(filename)
+ end
+
+ def verify(cert)
+ error, crl_map = do_verify(cert)
+ if error
+ [[false, cert, crl_map[cert.subject], error]]
+ else
+ @x509store.chain.collect { |c| [true, c, crl_map[c.subject], nil] }
+ end
+ end
+
+ def match_cert(cert1, cert2)
+ (cert1.issuer.cmp(cert2.issuer) == 0) and cert1.serial == cert2.serial
+ end
+
+ def is_ca?(cert)
+ case guess_cert_type(cert)
+ when CERT_TYPE_SELF_SIGNED
+ true
+ when CERT_TYPE_OTHER
+ true
+ else
+ false
+ end
+ end
+
+ def scan_certs
+ @self_signed_ca = []
+ @other_ca = []
+ @ee = []
+ @crl = []
+ @request = []
+ load_certs
+ end
+
+private
+
+ def add_path
+ @x509store.add_path(@certs_dir)
+ end
+
+ def do_verify(cert)
+ error_map = {}
+ crl_map = {}
+ result = @x509store.verify(cert) do |ok, ctx|
+ cert = ctx.current_cert
+ if ctx.current_crl
+ crl_map[cert.subject] = true
+ end
+ if ok
+ if !ctx.current_crl
+ if crl = @crl_store.find_crl(cert)
+ crl_map[cert.subject] = true
+ if crl.revoked.find { |revoked| revoked.serial == cert.serial }
+ ok = false
+ error_string = 'certification revoked'
+ end
+ end
+ end
+ end
+ error_map[cert.subject] = error_string if error_string
+ ok
+ end
+ error = if result
+ nil
+ else
+ error_map[cert.subject] || @x509store.error_string
+ end
+ return error, crl_map
+ end
+
+ def load_certs
+ @c_store.get_certs.each do |certfile|
+ cert = generate_cert(certfile)
+ case guess_cert_type(cert)
+ when CERT_TYPE_SELF_SIGNED
+ @self_signed_ca << cert
+ when CERT_TYPE_OTHER
+ @other_ca << cert
+ when CERT_TYPE_EE
+ @ee << cert
+ else
+ raise "Unknown cert type."
+ end
+ end
+ @c_store.get_crls.each do |crlfile|
+ @crl << generate_cert(crlfile)
+ end
+ end
+
+ CERT_TYPE_SELF_SIGNED = 0
+ CERT_TYPE_OTHER = 1
+ CERT_TYPE_EE = 2
+ def guess_cert_type(cert)
+ ca = self_signed = is_cert_self_signed(cert)
+ cert.extensions.each do |ext|
+ # Ignores criticality of extensions. It's 'guess'ing.
+ case ext.oid
+ when 'basicConstraints'
+ /CA:(TRUE|FALSE), pathlen:(\d+)/ =~ ext.value
+ ca = ($1 == 'TRUE') unless ca
+ when 'keyUsage'
+ usage = ext.value.split(/\s*,\s*/)
+ ca = usage.include?('Certificate Sign') unless ca
+ when 'nsCertType'
+ usage = ext.value.split(/\s*,\s*/)
+ ca = usage.include?('SSL CA') unless ca
+ end
+ end
+ if ca
+ if self_signed
+ CERT_TYPE_SELF_SIGNED
+ else
+ CERT_TYPE_OTHER
+ end
+ else
+ CERT_TYPE_EE
+ end
+ end
+
+ def is_cert_self_signed(cert)
+ # cert.subject.cmp(cert.issuer) == 0
+ cert.subject.to_s == cert.issuer.to_s
+ end
+end
+
+
+if $0 == __FILE__
+ c = CertStore.new("trust_certs")
+end
diff --git a/sample/openssl/cipher.rb b/sample/openssl/cipher.rb
new file mode 100644
index 00000000000..844b6eea4ee
--- /dev/null
+++ b/sample/openssl/cipher.rb
@@ -0,0 +1,29 @@
+#!/usr/bin/env ruby
+require 'openssl'
+
+text = "abcdefghijklmnopqrstuvwxyz"
+key = "key"
+alg = "DES-EDE3-CBC"
+#alg = "AES-128-CBC"
+
+puts "--Setup--"
+puts %(clear text: "#{text}")
+puts %(symmetric key: "#{key}")
+puts %(cipher alg: "#{alg}")
+puts
+
+puts "--Encrypting--"
+des = OpenSSL::Cipher::Cipher.new(alg)
+des.encrypt(key) #, "iv12345678")
+cipher = des.update(text)
+cipher << des.final
+puts %(encrypted text: #{cipher.inspect})
+puts
+
+puts "--Decrypting--"
+des = OpenSSL::Cipher::Cipher.new(alg)
+des.decrypt(key) #, "iv12345678")
+out = des.update(cipher)
+out << des.final
+puts %(decrypted text: "#{out}")
+puts
diff --git a/sample/openssl/crlstore.rb b/sample/openssl/crlstore.rb
new file mode 100644
index 00000000000..b305913eb05
--- /dev/null
+++ b/sample/openssl/crlstore.rb
@@ -0,0 +1,122 @@
+begin
+ require 'http-access2'
+rescue LoadError
+ STDERR.puts("Cannot load http-access2. CRL might not be fetched.")
+end
+require 'c_rehash'
+
+
+class CrlStore
+ def initialize(c_store)
+ @c_store = c_store
+ @c_store.hash_dir(true)
+ end
+
+ def find_crl(cert)
+ do_find_crl(cert)
+ end
+
+private
+
+ def do_find_crl(cert)
+ unless ca = find_ca(cert)
+ return nil
+ end
+ unless crlfiles = @c_store.get_crls(ca.subject)
+ if crl = renew_crl(cert, ca)
+ @c_store.add_crl(crl)
+ return crl
+ end
+ return nil
+ end
+ crlfiles.each do |crlfile|
+ next unless crl = load_crl(crlfile)
+ if crl.next_update < Time.now
+ if new_crl = renew_crl(cert, ca)
+ @c_store.delete_crl(crl)
+ @c_store.add_crl(new_crl)
+ crl = new_crl
+ end
+ end
+ if check_valid(crl, ca)
+ return crl
+ end
+ end
+ nil
+ end
+
+ def find_ca(cert)
+ @c_store.get_certs(cert.issuer).each do |cafile|
+ ca = load_cert(cafile)
+ if cert.verify(ca.public_key)
+ return ca
+ end
+ end
+ nil
+ end
+
+ def fetch(location)
+ if /\AURI:(.*)\z/ =~ location
+ begin
+ c = HTTPAccess2::Client.new(ENV['http_proxy'] || ENV['HTTP_PROXY'])
+ c.get_content($1)
+ rescue NameError, StandardError
+ nil
+ end
+ else
+ nil
+ end
+ end
+
+ def load_cert(certfile)
+ load_cert_str(File.read(certfile))
+ end
+
+ def load_crl(crlfile)
+ load_crl_str(File.read(crlfile))
+ end
+
+ def load_cert_str(cert_str)
+ OpenSSL::X509::Certificate.new(cert_str)
+ end
+
+ def load_crl_str(crl_str)
+ OpenSSL::X509::CRL.new(crl_str)
+ end
+
+ def check_valid(crl, ca)
+ unless crl.verify(ca.public_key)
+ return false
+ end
+ crl.last_update <= Time.now
+ end
+
+ RE_CDP = /\AcrlDistributionPoints\z/
+ def get_cdp(cert)
+ if cdp_ext = cert.extensions.find { |ext| RE_CDP =~ ext.oid }
+ cdp_ext.value.chomp
+ else
+ false
+ end
+ end
+
+ def renew_crl(cert, ca)
+ if cdp = get_cdp(cert)
+ if new_crl_str = fetch(cdp)
+ new_crl = load_crl_str(new_crl_str)
+ if check_valid(new_crl, ca)
+ return new_crl
+ end
+ end
+ end
+ false
+ end
+end
+
+if $0 == __FILE__
+ dir = "trust_certs"
+ c_store = CHashDir.new(dir)
+ s = CrlStore.new(c_store)
+ c = OpenSSL::X509::Certificate.new(File.read("cert_store/google_codesign.pem"))
+ p s.find_crl(c)
+end
diff --git a/sample/openssl/echo_cli.rb b/sample/openssl/echo_cli.rb
new file mode 100644
index 00000000000..29b356a7ad4
--- /dev/null
+++ b/sample/openssl/echo_cli.rb
@@ -0,0 +1,37 @@
+#!/usr/bin/env ruby
+
+require 'socket'
+require 'openssl'
+require 'getopts'
+
+getopts nil, "p:2000", "c:", "k:", "C:"
+
+host = ARGV[0] || "localhost"
+port = $OPT_p
+cert_file = $OPT_c
+key_file = $OPT_k
+ca_path = $OPT_C
+
+ctx = OpenSSL::SSL::SSLContext.new()
+if cert_file && key_file
+ ctx.cert = OpenSSL::X509::Certificate.new(File::read(cert_file))
+ ctx.key = OpenSSL::PKey::RSA.new(File::read(key_file))
+end
+if ca_path
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ ctx.ca_path = ca_path
+else
+ $stderr.puts "!!! WARNING: PEER CERTIFICATE WON'T BE VERIFIED !!!"
+end
+
+s = TCPSocket.new(host, port)
+ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
+ssl.connect # start SSL session
+ssl.sync_close = true # if true the underlying socket will be
+ # closed in SSLSocket#close. (default: false)
+while line = $stdin.gets
+ ssl.write line
+ print ssl.gets
+end
+
+ssl.close
diff --git a/sample/openssl/echo_svr.rb b/sample/openssl/echo_svr.rb
new file mode 100644
index 00000000000..be8e10fa26c
--- /dev/null
+++ b/sample/openssl/echo_svr.rb
@@ -0,0 +1,62 @@
+#!/usr/bin/env ruby
+
+require 'socket'
+require 'openssl'
+require 'getopts'
+
+getopts nil, "p:2000", "c:", "k:", "C:"
+
+port = $OPT_p
+cert_file = $OPT_c
+key_file = $OPT_k
+ca_path = $OPT_C
+
+if cert_file && key_file
+ cert = OpenSSL::X509::Certificate.new(File::read(cert_file))
+ key = OpenSSL::PKey::RSA.new(File::read(key_file))
+else
+ key = OpenSSL::PKey::RSA.new(512){ print "." }
+ puts
+ cert = OpenSSL::X509::Certificate.new
+ cert.version = 2
+ cert.serial = 0
+ name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]])
+ cert.subject = name
+ cert.issuer = name
+ cert.not_before = Time.now
+ cert.not_after = Time.now + 3600
+ cert.public_key = key.public_key
+ ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
+ cert.extensions = [
+ ef.create_extension("basicConstraints","CA:FALSE"),
+ ef.create_extension("subjectKeyIdentifier","hash"),
+ ef.create_extension("extendedKeyUsage","serverAuth"),
+ ef.create_extension("keyUsage",
+ "keyEncipherment,dataEncipherment,digitalSignature")
+ ]
+ ef.issuer_certificate = cert
+ cert.add_extension ef.create_extension("authorityKeyIdentifier",
+ "keyid:always,issuer:always")
+ cert.sign(key, OpenSSL::Digest::SHA1.new)
+end
+
+ctx = OpenSSL::SSL::SSLContext.new()
+ctx.key = key
+ctx.cert = cert
+if ca_path
+ ctx.verify_mode =
+ OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
+ ctx.ca_path = ca_path
+else
+ $stderr.puts "!!! WARNING: PEER CERTIFICATE WON'T BE VERIFIED !!!"
+end
+
+tcps = TCPServer.new(port)
+ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)
+loop do
+ ns = ssls.accept
+ while line = ns.gets
+ ns.write line
+ end
+ ns.close
+end
diff --git a/sample/openssl/gen_csr.rb b/sample/openssl/gen_csr.rb
new file mode 100644
index 00000000000..c22073b9b9a
--- /dev/null
+++ b/sample/openssl/gen_csr.rb
@@ -0,0 +1,52 @@
+#!/usr/bin/env ruby
+
+require 'getopts'
+require 'openssl'
+
+include OpenSSL
+
+def usage
+ myname = File::basename($0)
+ $stderr.puts <<EOS
+Usage: #{myname} name [keypair_file]
+ name ... ex. /C=JP/O=RRR/OU=CA/CN=NaHi/emailAddress=nahi@example.org
+EOS
+ exit
+end
+
+getopts nil, "key:", "csrout:", "keyout:"
+keypair_file = $OPT_key
+csrout = $OPT_csrout || "csr.pem"
+keyout = $OPT_keyout || "keypair.pem"
+
+name_str = ARGV.shift or usage()
+
+$stdout.sync = true
+
+name_ary = name_str.scan(/\s*([^\/,]+)\s*/).collect { |i| i[0].split("=") }
+p name_ary
+name = X509::Name.new(name_ary)
+
+keypair = nil
+if keypair_file
+ keypair = PKey::RSA.new(File.read(keypair_file))
+else
+ keypair = PKey::RSA.new(1024) { putc "." }
+ puts
+ puts "Writing #{keyout}..."
+ File.open(keyout, "w", 0400) do |f|
+ f << keypair.to_pem
+ end
+end
+
+puts "Generating CSR for #{name_ary.inspect}"
+
+req = X509::Request.new
+req.subject = name
+req.public_key = keypair.public_key
+req.sign(keypair, Digest::SHA1.new)
+
+puts "Writing #{csrout}..."
+File.open(csrout, "w") do |f|
+ f << req.to_pem
+end
diff --git a/sample/openssl/smime_read.rb b/sample/openssl/smime_read.rb
new file mode 100644
index 00000000000..0f08f54f7e2
--- /dev/null
+++ b/sample/openssl/smime_read.rb
@@ -0,0 +1,23 @@
+require 'getopts'
+require 'openssl'
+include OpenSSL
+
+getopts nil, "c:", "k:", "C:"
+
+cert_file = $OPT_c
+key_file = $OPT_k
+ca_path = $OPT_C
+
+data = $stdin.read
+
+cert = X509::Certificate.new(File::read(cert_file))
+key = PKey::RSA.new(File::read(key_file))
+p7enc = PKCS7::read_smime(data)
+data = p7enc.decrypt(key, cert)
+
+store = X509::Store.new
+store.add_path(ca_path)
+p7sig = PKCS7::read_smime(data)
+if p7sig.verify([], store)
+ puts p7sig.data
+end
diff --git a/sample/openssl/smime_write.rb b/sample/openssl/smime_write.rb
new file mode 100644
index 00000000000..ce32cd8146e
--- /dev/null
+++ b/sample/openssl/smime_write.rb
@@ -0,0 +1,23 @@
+require 'openssl'
+require 'getopts'
+include OpenSSL
+
+getopts nil, "c:", "k:", "r:"
+
+cert_file = $OPT_c
+key_file = $OPT_k
+rcpt_file = $OPT_r
+
+cert = X509::Certificate.new(File::read(cert_file))
+key = PKey::RSA.new(File::read(key_file))
+
+data = "Content-Type: text/plain\r\n"
+data << "\r\n"
+data << "This is a clear-signed message.\r\n"
+
+p7sig = PKCS7::sign(cert, key, data, [], PKCS7::DETACHED)
+smime0 = PKCS7::write_smime(p7sig)
+
+rcpt = X509::Certificate.new(File::read(rcpt_file))
+p7enc = PKCS7::encrypt([rcpt], smime0)
+print PKCS7::write_smime(p7enc)
diff --git a/sample/openssl/wget.rb b/sample/openssl/wget.rb
new file mode 100644
index 00000000000..0362ab980d7
--- /dev/null
+++ b/sample/openssl/wget.rb
@@ -0,0 +1,33 @@
+#!/usr/bin/env ruby
+
+require 'net/https'
+require 'getopts'
+
+getopts nil, 'C:'
+
+ca_path = $OPT_C
+
+uri = URI.parse(ARGV[0])
+if proxy = ENV['HTTP_PROXY']
+ prx_uri = URI.parse(proxy)
+ prx_host = prx_uri.host
+ prx_port = prx_uri.port
+end
+
+h = Net::HTTP.new(uri.host, uri.port, prx_host, prx_port)
+h.set_debug_output($stderr) if $DEBUG
+if uri.scheme == "https"
+ h.use_ssl = true
+ if ca_path
+ h.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ h.ca_path = ca_path
+ else
+ $stderr.puts "!!! WARNING: PEER CERTIFICATE WON'T BE VERIFIED !!!"
+ end
+end
+
+path = uri.path.empty? ? "/" : uri.path
+h.get2(path){|resp|
+ STDERR.puts h.peer_cert.inspect if h.peer_cert
+ print resp.body
+}