From ccdc8d302adfe78d0f49c4a50755bc320b39f821 Mon Sep 17 00:00:00 2001 From: nahi Date: Fri, 25 Jul 2003 15:12:26 +0000 Subject: [PATCH] * ext/openssl/sample: Add samples. - cert2text.rb: Dump certificate file as text. - crlstore.rb: CRL store implementation. Fetch CRL via HTTP when http-access2 is installed. - certstore.rb: Certificate store implementation. - cert_store_view.rb: Certificate store viewer with FXRuby. Uses c_rehash.rb, crlstore.rb and certstore.rb. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4160 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 20 +- ext/openssl/sample/cert2text.rb | 23 + ext/openssl/sample/cert_store_view.rb | 911 ++++++++++++++++++++++++++ ext/openssl/sample/certstore.rb | 161 +++++ ext/openssl/sample/crlstore.rb | 122 ++++ 5 files changed, 1232 insertions(+), 5 deletions(-) create mode 100644 ext/openssl/sample/cert2text.rb create mode 100644 ext/openssl/sample/cert_store_view.rb create mode 100644 ext/openssl/sample/certstore.rb create mode 100644 ext/openssl/sample/crlstore.rb diff --git a/ChangeLog b/ChangeLog index 8a1e4f4314..0ba372a4ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Fri Jul 25 15:04:25 2003 NAKAMURA, Hiroshi + + * ext/openssl/sample: Add samples. + - cert2text.rb: Dump certificate file as text. + - crlstore.rb: CRL store implementation. Fetch CRL via HTTP when + http-access2 is installed. + - certstore.rb: Certificate store implementation. + - cert_store_view.rb: Certificate store viewer with FXRuby. Uses + c_rehash.rb, crlstore.rb and certstore.rb. + Fri Jul 25 15:47:39 2003 GOTOU Yuuzou * ext/openssl/extconf.rb: add check for BN_rand_range() and @@ -855,7 +865,7 @@ Thu Jun 19 13:13:10 2003 NAKAMURA Usaku * hash.c (env_delete, rb_f_getenv, env_fetch): case insensitive to access environment variables on DOSISH platforms. -Thu Jun 19 00:51:47 2003 NAKAMURA Hiroshi +Thu Jun 19 00:51:47 2003 NAKAMURA, Hiroshi * range.c (rb_range_beg_len): out_of_range check after adjusting end point. [ruby-dev:20370] @@ -2996,7 +3006,7 @@ Wed Feb 26 17:38:16 2003 Tanaka Akira * lib/open-uri.rb: replace Kernel.open as well. -Tue Feb 25 23:03:08 2003 NAKAMURA Hiroshi +Tue Feb 25 23:03:08 2003 NAKAMURA, Hiroshi * lib/debug.rb (DEBUGGER__::Context#debug_command): bp filename must be the basename of it. [ruby-talk:65644] @@ -4889,7 +4899,7 @@ Sun Nov 17 22:57:31 2002 Nobuyoshi Nakada * parse.y (dsym): garbage returned. (ruby-bugs-ja:PR#358) -Fri Nov 15 07:40:08 2002 NAKAMURA Hiroshi +Fri Nov 15 07:40:08 2002 NAKAMURA, Hiroshi * observer.rb: raise NoMethodError instead of NameError. [ruby-dev:18788] @@ -13961,7 +13971,7 @@ Fri Dec 29 00:38:46 2000 Yukihiro Matsumoto * m17n.c: new file - core functions of M17N. -Tue Dec 26 18:46:41 2000 NAKAMURA Hiroshi +Tue Dec 26 18:46:41 2000 NAKAMURA, Hiroshi * lib/debug.rb: Avoid thread deadlock in debugging stopped thread. @@ -18516,7 +18526,7 @@ Fri Jul 16 01:37:50 1999 Koji Arai * string.c (rb_str_reverse): should always return copy. -Thu Jul 15 23:25:57 1999 NAKAMURA Hiroshi +Thu Jul 15 23:25:57 1999 NAKAMURA, Hiroshi * lib/debug.rb: better display & frame treatment. diff --git a/ext/openssl/sample/cert2text.rb b/ext/openssl/sample/cert2text.rb new file mode 100644 index 0000000000..50da224e76 --- /dev/null +++ b/ext/openssl/sample/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/ext/openssl/sample/cert_store_view.rb b/ext/openssl/sample/cert_store_view.rb new file mode 100644 index 0000000000..26c4d527f7 --- /dev/null +++ b/ext/openssl/sample/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 + < 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/ext/openssl/sample/certstore.rb b/ext/openssl/sample/certstore.rb new file mode 100644 index 0000000000..bbc637f668 --- /dev/null +++ b/ext/openssl/sample/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/ext/openssl/sample/crlstore.rb b/ext/openssl/sample/crlstore.rb new file mode 100644 index 0000000000..b305913eb0 --- /dev/null +++ b/ext/openssl/sample/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