11
module CertDumpSupport
14
cert.extensions.find { |ext| ext.oid == 'subjectAltName' }
16
subject_alt_name.value.split(/\s*,\s/).each do |alt_name_pair|
17
alt_tag, alt_name = alt_name_pair.split(/:/)
21
name_label(cert.subject)
26
if (cn = ary.find { |rdn| rdn[0] == 'CN' })
29
if ary.last[0] == 'OU'
36
name.to_a.collect { |tag, value|
42
("0" << sprintf("%X", bn)).scan(/../).join(" ")
47
include CertDumpSupport
59
when 'Signature Algorithm'
78
def get_dump_line(tag)
84
when 'Signature Algorithm'
85
signature_algorithm_line
106
"Version: #{@cert.version + 1}"
114
bn_label(@cert.serial)
121
def signature_algorithm
122
@cert.signature_algorithm
125
def signature_algorithm_line
130
name_text(@cert.subject)
138
name_text(@cert.issuer)
147
Not before: #{not_before}
148
Not after: #{not_after}
153
"from #{@cert.not_before.iso8601} to #{@cert.not_after.iso8601}"
157
@cert.not_before.to_s
173
@cert.public_key.to_text
177
"#{@cert.public_key.class} -- " << public_key.scan(/\A[^\n]*/)[0] << '...'
181
@cert.extensions.each do |ext|
183
return ext_detail(tag, ext.value)
190
ext(tag).tr("\r\n", '')
193
def ext_detail(tag, value)
199
include CertDumpSupport
209
when 'Signature Algorithm'
222
def get_dump_line(tag)
226
when 'Signature Algorithm'
227
signature_algorithm_line
242
"Version: #{@crl.version + 1}"
249
def signature_algorithm
250
@crl.signature_algorithm
253
def signature_algorithm_line
258
name_text(@crl.issuer)
266
@crl.last_update.to_s
274
@crl.next_update.to_s
282
@crl.extensions.each do |ext|
284
return ext_detail(tag, ext.value)
291
ext(tag).tr("\r\n", '')
294
def ext_detail(tag, value)
300
include CertDumpSupport
302
def initialize(revoked)
317
def get_dump_line(tag)
331
bn_label(@revoked.serial)
347
@revoked.extensions.each do |ext|
349
return ext_detail(tag, ext.value)
356
ext(tag).tr("\r\n", '')
359
def ext_detail(tag, value)
365
include CertDumpSupport
375
when 'Signature Algorithm'
386
def get_dump_line(tag)
390
when 'Signature Algorithm'
391
signature_algorithm_line
404
"Version: #{@req.version + 1}"
411
def signature_algorithm
412
@req.signature_algorithm
415
def signature_algorithm_line
420
name_text(@req.subject)
428
@req.public_key.to_text
432
"#{@req.public_key.class} -- " << public_key.scan(/\A[^\n]*/)[0] << '...'
439
def attributes_line(tag)
440
attributes(tag).tr("\r\n", '')
444
class CertStoreView < FXMainWindow
446
include CertDumpSupport
448
def initialize(observer, tree)
451
@tree.connect(SEL_COMMAND) do |sender, sel, item|
453
@observer.getApp().beginWaitCursor do
454
@observer.show_item(item.data)
457
@observer.show_item(nil)
464
@self_signed_ca_node = add_item_last(nil, "Trusted root CA")
465
@other_ca_node = add_item_last(nil, "Intermediate CA")
466
@ee_node = add_item_last(nil, "Personal")
467
@crl_node = add_item_last(nil, "CRL")
468
@request_node = add_item_last(nil, "Request")
469
@verify_path_node = add_item_last(nil, "Certification path")
470
show_certs(cert_store)
473
def show_certs(cert_store)
474
remove_items(@self_signed_ca_node)
475
remove_items(@other_ca_node)
476
remove_items(@ee_node)
477
remove_items(@crl_node)
478
remove_items(@request_node)
479
import_certs(cert_store)
482
def show_request(req)
483
node = add_item_last(@request_node, name_label(req.subject), req)
484
@tree.selectItem(node)
485
@observer.show_item(req)
488
def show_verify_path(verify_path)
489
add_verify_path(verify_path)
495
node.expanded = node.opened = true
499
node.expanded = node.opened = false
502
def import_certs(cert_store)
503
cert_store.self_signed_ca.each do |cert|
504
add_item_last(@self_signed_ca_node, cert_label(cert), cert)
506
cert_store.other_ca.each do |cert|
507
add_item_last(@other_ca_node, cert_label(cert), cert)
509
cert_store.ee.each do |cert|
510
add_item_last(@ee_node, cert_label(cert), cert)
512
cert_store.crl.each do |crl|
513
node = add_item_last(@crl_node, name_label(crl.issuer), crl)
515
crl.revoked.each do |revoked|
516
add_item_last(node, bn_label(revoked.serial), revoked)
519
cert_store.request.each do |req|
520
add_item_last(@requestnode, name_label(req.subject), req)
524
def add_verify_path(verify_path)
525
node = @verify_path_node
527
verify_path.reverse_each do |ok, cert, crl_check, error_string|
529
if @observer.cert_store.is_ca?(cert)
530
warn << 'NO ARL' unless crl_check
532
warn << 'NO CRL' unless crl_check
534
warn_str = '(' << warn.join(", ") << ')'
535
warn_mark = warn.empty? ? '' : '!'
537
"OK#{warn_mark}..." + cert_label(cert)
539
"NG(#{error_string})..." + cert_label(cert)
541
label << warn_str unless warn.empty?
542
node = add_item_last(node, label, cert)
547
@tree.selectItem(node)
548
@observer.show_item(last_cert)
552
def add_item_last(parent, label, obj = nil)
553
node = @tree.addItemLast(parent, FXTreeItem.new(label))
554
node.data = obj if obj
559
def remove_items(node)
560
while node.getNumChildren > 0
561
@tree.removeItem(node.getFirst)
567
def initialize(observer, table)
570
@table.leadingRows = 0
571
@table.leadingCols = 0
572
@table.trailingRows = 0
573
@table.trailingCols = 0
574
@table.showVertGrid(false)
575
@table.showHorzGrid(false)
576
@table.setTableSize(1, 2)
577
@table.setColumnWidth(0, 125)
578
@table.setColumnWidth(1, 350)
582
@observer.show_detail(nil, nil)
588
when OpenSSL::X509::Certificate
590
when OpenSSL::X509::CRL
592
when OpenSSL::X509::Revoked
594
when OpenSSL::X509::Request
597
raise NotImplementedError.new("Unknown item type #{item.class}.")
604
wrap = CertDump.new(cert)
606
items << ['Version', wrap.get_dump_line('Version')]
607
items << ['Signature Algorithm', wrap.get_dump_line('Signature Algorithm')]
608
items << ['Issuer', wrap.get_dump_line('Issuer')]
609
items << ['Serial', wrap.get_dump_line('Serial')]
610
#items << ['Not before', wrap.get_dump_line('Not before')]
611
#items << ['Not after', wrap.get_dump_line('Not after')]
612
items << ['Subject', wrap.get_dump_line('Subject')]
613
items << ['Public key', wrap.get_dump_line('Public key')]
614
items << ['Validity', wrap.get_dump_line('Validity')]
615
(cert.extensions.sort { |a, b| a.oid <=> b.oid }).each do |ext|
616
items << [ext.oid, wrap.get_dump_line(ext.oid)]
618
show_items(cert, items)
622
wrap = CrlDump.new(crl)
624
items << ['Version', wrap.get_dump_line('Version')]
625
items << ['Signature Algorithm', wrap.get_dump_line('Signature Algorithm')]
626
items << ['Issuer', wrap.get_dump_line('Issuer')]
627
items << ['Last update', wrap.get_dump_line('Last update')]
628
items << ['Next update', wrap.get_dump_line('Next update')]
629
crl.extensions.each do |ext|
630
items << [ext.oid, wrap.get_dump_line(ext.oid)]
632
show_items(crl, items)
635
def show_revoked(revoked)
636
wrap = RevokedDump.new(revoked)
638
items << ['Serial', wrap.get_dump_line('Serial')]
639
items << ['Time', wrap.get_dump_line('Time')]
640
revoked.extensions.each do |ext|
641
items << [ext.oid, wrap.get_dump_line(ext.oid)]
643
show_items(revoked, items)
646
def show_request(req)
647
wrap = RequestDump.new(req)
649
items << ['Version', wrap.get_dump_line('Version')]
650
items << ['Signature Algorithm', wrap.get_dump_line('Signature Algorithm')]
651
items << ['Subject', wrap.get_dump_line('Subject')]
652
items << ['Public key', wrap.get_dump_line('Public key')]
653
req.attributes.each do |attr|
654
items << [attr.attr, wrap.get_dump_line(attr.oid)]
656
show_items(req, items)
659
def show_items(obj, items)
660
set_column_size(items.size)
661
items.each_with_index do |ele, idx|
663
@table.setItemText(idx, 0, tag)
664
@table.getItem(idx, 0).data = tag
665
@table.setItemText(idx, 1, value.to_s)
666
@table.getItem(idx, 1).data = tag
668
@table.connect(SEL_COMMAND) do |sender, sel, loc|
669
item = @table.getItem(loc.row, loc.col)
670
@observer.show_detail(obj, item.data)
675
def set_column_size(size)
676
col0_width = @table.getColumnWidth(0)
677
col1_width = @table.getColumnWidth(1)
678
@table.setTableSize(size, 2)
679
@table.setColumnWidth(0, col0_width)
680
@table.setColumnWidth(1, col1_width)
684
for col in 0..@table.numCols-1
685
for row in 0..@table.numRows-1
686
@table.getItem(row, col).justify = FXTableItem::LEFT
693
def initialize(observer, detail)
704
when OpenSSL::X509::Certificate
706
when OpenSSL::X509::CRL
708
when OpenSSL::X509::Revoked
709
show_revoked(item, tag)
710
when OpenSSL::X509::Request
711
show_request(item, tag)
713
raise NotImplementedError.new("Unknown item type #{item.class}.")
719
def show_cert(cert, tag)
720
wrap = CertDump.new(cert)
721
@detail.text = wrap.get_dump(tag)
724
def show_crl(crl, tag)
725
wrap = CrlDump.new(crl)
726
@detail.text = wrap.get_dump(tag)
729
def show_revoked(revoked, tag)
730
wrap = RevokedDump.new(revoked)
731
@detail.text = wrap.get_dump(tag)
734
def show_request(request, tag)
735
wrap = RequestDump.new(request)
736
@detail.text = wrap.get_dump(tag)
740
attr_reader :cert_store
742
def initialize(app, cert_store)
743
@cert_store = cert_store
745
@verify_filename = nil
750
super(app, "Certificate store", nil, nil, DECOR_ALL, 0, 0, full_width,
753
FXTooltip.new(self.getApp())
755
menubar = FXMenubar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
756
file_menu = FXMenuPane.new(self)
757
FXMenuTitle.new(menubar, "&File", nil, file_menu)
758
file_open_menu = FXMenuPane.new(self)
759
FXMenuCommand.new(file_open_menu, "&Directory\tCtl-O").connect(SEL_COMMAND,
760
method(:on_cmd_file_open_dir))
761
FXMenuCascade.new(file_menu, "&Open\tCtl-O", nil, file_open_menu)
762
FXMenuCommand.new(file_menu, "&Quit\tCtl-Q", nil, getApp(), FXApp::ID_QUIT)
764
tool_menu = FXMenuPane.new(self)
765
FXMenuTitle.new(menubar, "&Tool", nil, tool_menu)
766
FXMenuCommand.new(tool_menu, "&Verify\tCtl-N").connect(SEL_COMMAND,
767
method(:on_cmd_tool_verify))
768
FXMenuCommand.new(tool_menu, "&Show Request\tCtl-R").connect(SEL_COMMAND,
769
method(:on_cmd_tool_request))
771
base_frame = FXHorizontalFrame.new(self, LAYOUT_FILL_X | LAYOUT_FILL_Y)
772
splitter_horz = FXSplitter.new(base_frame, LAYOUT_SIDE_TOP | LAYOUT_FILL_X |
773
LAYOUT_FILL_Y | SPLITTER_TRACKING | SPLITTER_HORIZONTAL)
776
cert_tree_frame = FXHorizontalFrame.new(splitter_horz, LAYOUT_FILL_X |
777
LAYOUT_FILL_Y | FRAME_SUNKEN | FRAME_THICK)
778
cert_tree_frame.setWidth(horz_pos)
779
cert_tree = FXTreeList.new(cert_tree_frame, 0, nil, 0,
780
TREELIST_BROWSESELECT | TREELIST_SHOWS_LINES | TREELIST_SHOWS_BOXES |
781
TREELIST_ROOT_BOXES | LAYOUT_FILL_X | LAYOUT_FILL_Y)
782
@cert_tree = CertTree.new(self, cert_tree)
785
splitter_vert = FXSplitter.new(splitter_horz, LAYOUT_SIDE_TOP |
786
LAYOUT_FILL_X | LAYOUT_FILL_Y | SPLITTER_TRACKING | SPLITTER_VERTICAL |
788
cert_list_base = FXVerticalFrame.new(splitter_vert, LAYOUT_FILL_X |
789
LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0)
790
cert_list_frame = FXHorizontalFrame.new(cert_list_base, FRAME_SUNKEN |
791
FRAME_THICK | LAYOUT_FILL_X | LAYOUT_FILL_Y)
792
cert_info = FXTable.new(cert_list_frame, 2, 10, nil, 0, FRAME_SUNKEN |
793
TABLE_COL_SIZABLE | LAYOUT_FILL_X | LAYOUT_FILL_Y, 0, 0, 0, 0, 2, 2, 2, 2)
794
@cert_info = CertInfo.new(self, cert_info)
796
cert_detail_base = FXVerticalFrame.new(splitter_vert, LAYOUT_FILL_X |
797
LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0)
798
cert_detail_frame = FXHorizontalFrame.new(cert_detail_base, FRAME_SUNKEN |
799
FRAME_THICK | LAYOUT_FILL_X | LAYOUT_FILL_Y)
800
cert_detail = FXText.new(cert_detail_frame, nil, 0, TEXT_READONLY |
801
LAYOUT_FILL_X | LAYOUT_FILL_Y)
802
@cert_detail = CertDetail.new(self, cert_detail)
809
show(PLACEMENT_SCREEN)
813
@cert_tree.show(@cert_store)
818
@cert_tree.show_certs(@cert_store)
821
def show_request(req)
822
@cert_tree.show_request(req)
825
def show_verify_path(verify_path)
826
@cert_tree.show_verify_path(verify_path)
830
@cert_info.show(item) if @cert_info
833
def show_detail(item, tag)
834
@cert_detail.show(item, tag) if @cert_detail
838
path = verify_certfile(certfile)
839
show_certs # CRL could be change.
840
show_verify_path(path)
845
def on_cmd_file_open_dir(sender, sel, ptr)
846
dir = FXFileDialog.getOpenDirectory(self, "Open certificate directory", ".")
849
@cert_store = CertStore.new(dir)
858
def on_cmd_tool_verify(sender, sel, ptr)
859
dialog = FXFileDialog.new(self, "Verify certificate")
861
dialog.patternList = ["All Files (*)", "PEM formatted certificate (*.pem)"]
862
dialog.currentPattern = @verify_filter
863
if dialog.execute != 0
864
@verify_filename = dialog.filename
865
verify(@verify_filename)
867
@verify_filter = dialog.currentPattern
871
def on_cmd_tool_request(sender, sel, ptr)
872
dialog = FXFileDialog.new(self, "Show request")
874
dialog.patternList = ["All Files (*)", "PEM formatted certificate (*.pem)"]
875
if dialog.execute != 0
876
req = @cert_store.generate_cert(dialog.filename)
882
def verify_certfile(filename)
884
cert = @cert_store.generate_cert(filename)
885
result = @cert_store.verify(cert)
886
@cert_store.scan_certs
895
msg = e.inspect + "\n" + e.backtrace.join("\n")
896
FXMessageBox.error(self, MBOX_OK, "Error", msg)
902
certs_dir = ARGV.shift or raise "#{$0} cert_dir"
904
app = FXApp.new("CertStore", "FoxTest")
905
cert_store = CertStore.new(certs_dir)
906
w = CertStoreView.new(app, cert_store)