From 1957b9f56c6feee1f149b63ad088c7afa3f5acdd Mon Sep 17 00:00:00 2001 From: Thomas Hooge Date: Fri, 12 Feb 2021 13:36:19 +0100 Subject: [PATCH] Added feature to check and change private key password --- lib/CA.pm | 3 +- lib/GUI.pm | 121 ++++++++++++++++++++++++++++++++++++++++++- lib/KEY.pm | 86 +++++++++++++++++++++++++++--- lib/OpenSSL.pm | 43 +++++++++++++++ templates/tinyca.cnf | 1 + 5 files changed, 243 insertions(+), 11 deletions(-) diff --git a/lib/CA.pm b/lib/CA.pm index c3f94d0..b7020de 100644 --- a/lib/CA.pm +++ b/lib/CA.pm @@ -132,6 +132,7 @@ sub open_ca { main::printd("Request-Type: " . ($self->{'cfg'}->{global}{default_req_type} // 'none')); main::printd("Default bits server: " . ($self->{'cfg'}->{server}{default_bits} // 'none')); main::printd("Default bits user: " . ($self->{'cfg'}->{user}{default_bits} // 'none')); + main::printd("Default key cipher: " . ($self->{'cfg'}->{user}{default_cipher} // 'none')); # update config (necessary for update from old tinyca) $cnf = $self->{$opts->{'name'}}->{'cnf'}; @@ -659,7 +660,7 @@ sub import_ca { $opts->{'cakeydata'} = $main->{'KEY'}->key_change_passwd( $main, $opts->{'cakeyfile'}, $opts->{'passwd'}, - $opts->{'newpasswd'}); + $opts->{'newpasswd'}, 'ca'); if($opts->{'cakeydata'} eq 1) { return; diff --git a/lib/GUI.pm b/lib/GUI.pm index ba8c45f..beb8552 100644 --- a/lib/GUI.pm +++ b/lib/GUI.pm @@ -1760,6 +1760,109 @@ sub show_key_import_dialog { return; } +# +# check key password +# +sub show_key_check_dialog { + my ($self, $keyfile) = @_; + + my ($box, $button_close, $button_check, $table, $label_result); + my ($entry, $passwd, $result); + + $passwd = ''; + + $button_close = Gtk2::Button->new_from_stock('gtk-close'); + $button_close->signal_connect('clicked', sub { $box->destroy() }); + + $box = GUI::HELPERS::dialog_box( + _("Check password"), _("Check password on private key file"), + $button_close); + + $table = Gtk2::Table->new(2, 3, 0); + $table->set_col_spacing(0, 10); + $box->vbox->add($table); + + $entry = GUI::HELPERS::entry_to_table( + _("Password:"), + \$passwd, $table, 0, 0); + $entry->grab_focus(); + + $button_check = Gtk2::Button->new(_("Check")); + $button_check->signal_connect('clicked', sub { + $passwd =~ s/^\s+|\s+$//g; + if(length($passwd) == 0) { + $label_result->set_label(_("Enter password")); + return; + } + $result = $self->{'OpenSSL'}->checkpass($keyfile, $passwd); + $label_result->set_label($result == 0 ? _("OK") : _("ERROR")); + }); + $table->attach_defaults($button_check, 2, 3, 0, 1); + + $label_result = Gtk2::Label->new(""); + $table->attach_defaults($label_result, 1, 2, 1, 2); + + $box->show_all(); + + return; +} + +# +# change password for key +# +sub show_key_passwd_dialog { + my ($self, $keyfile) = @_; + + my ($box, $button_ok, $button_cancel, $pwtable); + my ($entry_old, $entry_new1, $entry_new2); + my ($passwd, $newpasswd, $newpasswd2, $result); + + $button_ok = Gtk2::Button->new_from_stock('gtk-ok'); + $button_ok->signal_connect('clicked', sub { + if($newpasswd eq $newpasswd2) { + $result = $self->{'KEY'}->key_change_passwd($self, $keyfile, $passwd, $newpasswd, 'key'); + if($result == 0) { + main::printd("password changed"); + $box->destroy(); + } else { + GUI::HELPERS::print_error(_("Password change failed")); + } + } else { + GUI::HELPERS::print_warning(_("New password does not match")); + } + }); + + # $button_ok->grab_default(); + + $button_cancel = Gtk2::Button->new_from_stock('gtk-cancel'); + $button_cancel->signal_connect('clicked', sub { $box->destroy() }); + + $box = GUI::HELPERS::dialog_box( + _("Change password"), _("Change password on private key file"), + $button_ok, $button_cancel); + + $pwtable = Gtk2::Table->new(3, 2, 0); + $pwtable->set_col_spacing(0, 10); + $box->vbox->add($pwtable); + + $entry_old = GUI::HELPERS::entry_to_table( + _("Old password:"), + \$passwd, $pwtable, 0, 0); + $entry_old->grab_focus(); + + $entry_new1 = GUI::HELPERS::entry_to_table( + _("New password:"), + \$newpasswd, $pwtable, 1, 0); + $entry_new2 = GUI::HELPERS::entry_to_table( + _("Confirm password:"), + \$newpasswd2, $pwtable, 2, 0); + + $box->show_all(); + + return; + +} + # # get password for exporting keys # @@ -3060,15 +3163,29 @@ sub _create_key_menu { $self->{'keymenu'} = Gtk2::Menu->new(); + $item = Gtk2::ImageMenuItem->new( _("Check password")); + $item->signal_connect(activate => + sub { $self->{'KEY'}->check_passwd($self) }); + $image = Gtk2::Image->new_from_stock('gtk-info', 'menu'); + $item->set_image($image); + $self->{'keymenu'}->insert($item, -1); + + $item = Gtk2::ImageMenuItem->new( _("Change password")); + $item->signal_connect(activate => + sub { $self->{'KEY'}->set_password($self) }); + $image = Gtk2::Image->new_from_stock('gtk-convert', 'menu'); + $item->set_image($image); + $self->{'keymenu'}->insert($item, -1); + $item = Gtk2::ImageMenuItem->new( _("Export Key")); - $item->signal_connect(activate => + $item->signal_connect(activate => sub { $self->{'KEY'}->get_export_key($self) }); $image = Gtk2::Image->new_from_stock('gtk-save', 'menu'); $item->set_image($image); $self->{'keymenu'}->insert($item, -1); $item = Gtk2::ImageMenuItem->new( _("Delete Key")); - $item->signal_connect(activate => + $item->signal_connect(activate => sub { $self->{'KEY'}->get_del_key($self) }); $image = Gtk2::Image->new_from_stock('gtk-delete', 'menu'); $item->set_image($image); diff --git a/lib/KEY.pm b/lib/KEY.pm index 51fa4d2..2818eb3 100644 --- a/lib/KEY.pm +++ b/lib/KEY.pm @@ -473,8 +473,65 @@ sub _check_key { return($name); } +# +# Check password +# +sub check_passwd { + my ($self, $main) = @_; + + my ($keyname, $key, $keyfile); + + $key = $main->{'keybrowser'}->selection_dn(); + + if(not defined $key) { + GUI::HELPERS::print_info(_("Please select a Key first")); + return; + } + + $keyname = HELPERS::enc_base64($key); + $keyfile = $main->{'cadir'}."/keys/".$keyname.".pem"; + + if(not -s $keyfile) { + GUI::HELPERS::print_warning(_("Key file not found:".$keyfile)); + return; + } + + $main->show_key_check_dialog($keyfile); + + return; +} + +# +# Set new password for key +# +sub set_password { + my ($self, $main) = @_; + + my ($keyname, $key, $keyfile); + + $key = $main->{'keybrowser'}->selection_dn(); + + if(not defined $key) { + GUI::HELPERS::print_info(_("Please select a Key first")); + return; + } + + $keyname = HELPERS::enc_base64($key); + $keyfile = $main->{'cadir'}."/keys/".$keyname.".pem"; + + if(not -s $keyfile) { + GUI::HELPERS::print_warning(_("Key file not found:".$keyfile)); + return; + } + + $main->show_key_passwd_dialog($keyfile); + + return; + +} + sub key_change_passwd { - my ($self, $main, $file, $oldpass, $newpass) = @_; + my ($self, $main, $file, $oldpass, $newpass, $mode) = @_; my $opts = {}; my ($t, $ret, $ext); @@ -483,7 +540,7 @@ sub key_change_passwd { my($type); - # ckeck file format + # check file format open(KEY, "<$file") || do { $t = sprintf(_("Can't open Key file:\n%s"), $file); @@ -495,7 +552,7 @@ sub key_change_passwd { $inform = "PEM"; $type = "RSA"; last; - } elsif(/BEGIN RSA PRIVATE KEY/){ + } elsif(/BEGIN DSA PRIVATE KEY/){ $inform = "PEM"; $type = "DSA"; last; @@ -519,15 +576,28 @@ sub key_change_passwd { GUI::HELPERS::set_cursor($main, 0); if($ret eq 1) { - $t = _("Generating key failed"); - - if($ext =~ /unable to load Private Key/) { - $t .= _("The password for your old CA Key is wrong"); + if($mode eq 'ca') { + $t = _("Generating key failed"); + if($ext =~ /unable to load Private Key/) { + $t .= _("The password for your old CA Key is wrong"); + } + } else { + $t = _("Change password failed"); } GUI::HELPERS::print_warning(($t), $ext); - return($ret); + return(1); } + if($mode eq 'key') { + # Write out key with new password + open(OUT, ">$file") || do { + GUI::HELPERS::print_warning(sprintf(_("Can't open output file: %s: %s"), $file, $!)); + return(1); + }; + print OUT $ret; + close(OUT); + return(0); + } return($ret); } diff --git a/lib/OpenSSL.pm b/lib/OpenSSL.pm index 2a1eabb..1542ed3 100644 --- a/lib/OpenSSL.pm +++ b/lib/OpenSSL.pm @@ -989,6 +989,49 @@ sub convkey { return($tmp); } +sub checkpass { + my ($self, $keyfile, $passwd) = @_; + + my ($cmd, $ext, $ret, $pid, $type); + + # Check type: RSA or DSA + open(KEY, "<$keyfile") || do { + GUI::HELPERS::print_warning(sprintf(_("Can't open Key file:\n%s"), $keyfile)); + return(1); + }; + $type = "UNKNOWN"; + while() { + if(/BEGIN RSA PRIVATE KEY/) { + $type = "rsa"; + last; + } elsif(/BEGIN DSA PRIVATE KEY/){ + $type = "dsa"; + last; + } + } + if($type eq "UNKNOWN") { + GUI::HELPERS::print_warning(_("Invalid key encryption type")); + return(1); + } + + $cmd = "$self->{'bin'} $type -noout"; + $cmd .= " -in \"$keyfile\""; + $cmd .= " -passin env:SSLPASS"; + + $ENV{'SSLPASS'} = $passwd; + my($rdfh, $wtfh); + $ext = "$cmd\n\n"; + $pid = open3($wtfh, $rdfh, $rdfh, $cmd); + while(<$rdfh>) { + $ext .= $_; + } + waitpid($pid, 0); + $ret = $? >> 8; + delete($ENV{'SSLPASS'}); + + return($ret); +} + sub genp12 { my $self = shift; my $opts = { @_ }; diff --git a/templates/tinyca.cnf b/templates/tinyca.cnf index 3ff1be7..bb63837 100644 --- a/templates/tinyca.cnf +++ b/templates/tinyca.cnf @@ -2,6 +2,7 @@ use_metadb = no default_req_type = user default_domain = example.com +default_cipher = aes256 [server] default_bits = 4096