Imported former upstream version 0.7.5

This commit is contained in:
2016-12-05 19:21:56 +01:00
commit e136e7cbbf
28 changed files with 24757 additions and 0 deletions

1402
lib/CA.pm Normal file

File diff suppressed because it is too large Load Diff

713
lib/CERT.pm Normal file
View File

@@ -0,0 +1,713 @@
# Copyright (c) Stephan Martin <sm@sm-zone.net>
#
# $Id: CERT.pm,v 1.11 2006/06/28 21:50:41 sm Exp $
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
use strict;
package CERT;
use POSIX;
sub new {
my $that = shift;
my $class = ref($that) || $that;
my $self = {};
$self->{'OpenSSL'} = shift;
bless($self, $class);
}
#
# read certificates in directory into list
#
sub read_certlist {
my ($self, $certdir, $crlfile, $indexfile, $force, $main) = @_;
my($f, $certlist, $crl, $modt, $parsed, $tmp, $t, $c, $p, @files);
GUI::HELPERS::set_cursor($main, 1);
$certlist = [];
$modt = (stat($certdir))[9];
if(defined($self->{'lastread'}) &&
($self->{'lastread'} >= $modt) &&
not defined($force)) {
GUI::HELPERS::set_cursor($main, 0);
return(0);
}
$crl = $self->{'OpenSSL'}->parsecrl($crlfile, $force);
opendir(DIR, $certdir) || do {
GUI::HELPERS::set_cursor($main, 0);
$t = sprintf(_("Can't open Certificate directory: %s"), $certdir);
GUI::HELPERS::print_warning($t);
return(0);
};
while($f = readdir(DIR)) {
next if $f =~ /^\./;
push(@files, $f);
$c++;
}
$main->{'barbox'}->pack_start($main->{'progress'}, 0, 0, 0);
$main->{'progress'}->show();
foreach $f (@files) {
next if $f =~ /^\./;
$f =~ s/\.pem//;
$tmp = HELPERS::dec_base64($f);
next if not defined($tmp);
next if $tmp eq "";
if(defined($main)) {
$t = sprintf(_(" Read Certificate: %s"), $tmp);
GUI::HELPERS::set_status($main, $t);
$p += 100/$c;
if($p/100 <= 1) {
$main->{'progress'}->set_fraction($p/100);
while(Gtk2->events_pending) {
Gtk2->main_iteration;
}
}
}
my $debugf = $certdir."/".$f.".pem";
$parsed = $self->{'OpenSSL'}->parsecert($crlfile, $indexfile,
$certdir."/".$f.".pem", $force);
defined($parsed) || do {
GUI::HELPERS::set_cursor($main, 0);
GUI::HELPERS::print_error(_("Can't read Certificate"));
};
$tmp .= "%".$parsed->{'STATUS'};
push(@{$certlist}, $tmp);
}
@{$certlist} = sort(@{$certlist});
closedir(DIR);
$self->{'certlist'} = $certlist;
$self->{'lastread'} = time();
if(defined($main)) {
$main->{'progress'}->set_fraction(0);
$main->{'barbox'}->remove($main->{'progress'});
GUI::HELPERS::set_cursor($main, 0);
}
return(1); # got new list
}
#
# get information for renewing a certifikate
#
sub get_renew_cert {
my ($self, $main, $opts, $box) = @_;
my ($cert, $status, $t, $ca, $cadir);
$box->destroy() if(defined($box));
if((not defined($opts->{'certfile'})) ||
(not defined($opts->{'passwd'})) ||
($opts->{'certfile'} eq '') ||
($opts->{'passwd'} eq '')) {
$cert = $main->{'certbrowser'}->selection_dn();
if(not defined($cert)) {
GUI::HELPERS::print_info(_("Please select a Certificate first"));
return;
}
$ca = $main->{'certbrowser'}->selection_caname();
$cadir = $main->{'certbrowser'}->selection_cadir();
$status = $main->{'certbrowser'}->selection_status();
if($status eq _("VALID")) {
$t = sprintf(
_("Can't renew Certifikate with Status: %s\nPlease revoke the Certificate first"),
$status);
GUI::HELPERS::print_warning($t);
return;
}
$opts->{'certname'} = HELPERS::enc_base64($cert);
$opts->{'reqname'} = $opts->{'certname'};
$opts->{'certfile'} = $cadir."/certs/".$opts->{'certname'}.".pem";
$opts->{'keyfile'} = $cadir."/keys/".$opts->{'certname'}.".pem";
$opts->{'reqfile'} = $cadir."/req/".$opts->{'certname'}.".pem";
if((not -s $opts->{'certfile'}) ||
(not -s $opts->{'keyfile'}) ||
(not -s $opts->{'reqfile'})) {
$t = _("Key and Request are necessary for renewal of a Certificate\nRenewal is not possible!");
GUI::HELPERS::print_warning($t);
return;
}
$main->show_req_sign_dialog($opts);
return;
}
$main->{'REQ'}->sign_req($main, $opts);
return;
}
#
# get information for revoking a certifikate
#
sub get_revoke_cert {
my ($self, $main, $opts, $box) = @_;
my ($cert, $status, $t, $ca, $cadir);
$box->destroy() if(defined($box));
if((not defined($opts->{'certfile'})) ||
(not defined($opts->{'passwd'})) ||
($opts->{'certfile'} eq '') ||
($opts->{'passwd'} eq '')) {
$opts->{'certfile'} = $main->{'certbrowser'}->selection_fname();
if(not defined($opts->{'certfile'})) {
$t = _("Please select a Certificate first");
GUI::HELPERS::print_info($t);
return;
}
$ca = $main->{'certbrowser'}->selection_caname();
$cadir = $main->{'certbrowser'}->selection_cadir();
$cert = $main->{'certbrowser'}->selection_dn();
$status = $main->{'certbrowser'}->selection_status();
if($status ne _("VALID")) {
$t = sprintf(_("Can't revoke Certifikate with Status: %s"),
$status);
GUI::HELPERS::print_warning($t);
return;
}
$opts->{'certname'} = HELPERS::enc_base64($cert);
$opts->{'cert'} = $cert;
$main->show_cert_revoke_dialog($opts);
return;
}
$self->revoke_cert($main, $opts);
return;
}
#
# now really revoke the certificate
#
sub revoke_cert {
my ($self, $main, $opts) = @_;
my($ca, $cadir, $ret, $t, $ext, $reason);
$ca = $main->{'certbrowser'}->selection_caname();
$cadir = $main->{'certbrowser'}->selection_cadir();
GUI::HELPERS::set_cursor($main, 1);
if(defined($opts->{'reason'}) && $opts->{'reason'} ne '') {
$reason = $opts->{'reason'};
} else {
$reason = 'none';
}
($ret, $ext) = $self->{'OpenSSL'}->revoke(
'config' => $main->{'CA'}->{$ca}->{'cnf'},
'infile' => $cadir."/certs/".$opts->{'certname'}.".pem",
'pass' => $opts->{'passwd'},
'reason' => $reason
);
if($ret eq 1) {
GUI::HELPERS::set_cursor($main, 0);
$t = _("Wrong CA password given\nRevoking the Certificate failed");
GUI::HELPERS::print_warning($t, $ext);
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
return;
} elsif($ret eq 2) {
GUI::HELPERS::set_cursor($main, 0);
$t = _("CA Key not found\nRevoking the Certificate failed");
GUI::HELPERS::print_warning($t, $ext);
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
return;
} elsif($ret) {
GUI::HELPERS::set_cursor($main, 0);
$t = _("Revoking the Certificate failed");
GUI::HELPERS::print_warning($t, $ext);
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
return;
}
($ret, $ext) = $self->{'OpenSSL'}->newcrl(
'config' => $main->{'CA'}->{$ca}->{'cnf'},
'pass' => $opts->{'passwd'},
'crldays' => 365,
'outfile' => $cadir."/crl/crl.pem"
);
if (not -s $cadir."/crl/crl.pem" || $ret) {
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
GUI::HELPERS::set_cursor($main, 0);
GUI::HELPERS::print_error(
_("Generating a new Revocation List failed"), $ext);
}
$self->{'OpenSSL'}->parsecrl( $cadir."/crl/crl.pem", 1);
$self->reread_cert($main, $opts->{'cert'});
# force reread of certlist
$main->{'certbrowser'}->update($cadir."/certs",
$cadir."/crl/crl.pem",
$cadir."/index.txt",
0);
GUI::HELPERS::set_cursor($main, 0);
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
return;
}
#
# get name of certificatefile to delete
#
sub get_del_cert {
my ($self, $main) = @_;
my($certname, $cert, $certfile, $status, $t, $cadir, $ca);
$certfile = $main->{'certbrowser'}->selection_fname();
if(not defined $certfile) {
GUI::HELPERS::print_info(_("Please select a Certificate first"));
return;
}
$ca = $main->{'certbrowser'}->selection_caname();
$cadir = $main->{'certbrowser'}->selection_cadir();
$cert = $main->{'certbrowser'}->selection_dn();
$status = $main->{'certbrowser'}->selection_status();
$certname = HELPERS::enc_base64($cert);
if($status eq _("VALID")) {
GUI::HELPERS::print_warning(
_("Can't delete VALID certificate!\nPlease revoke the Certificate first."));
return;
}
$main->show_del_confirm($certfile, 'cert');
return;
}
#
# now really delete the certificatefile
#
sub del_cert {
my ($self, $main, $file) = @_;
GUI::HELPERS::set_cursor($main, 1);
unlink($file);
my $cadir = $main->{'certbrowser'}->selection_cadir();
$main->{'certbrowser'}->update($cadir."/certs",
$cadir."/crl/crl.pem",
$cadir."/index.txt",
0);
GUI::HELPERS::set_cursor($main, 0);
return;
}
#
# get informations for exporting a certificate
#
sub get_export_cert {
my ($self, $main, $opts, $box) = @_;
$box->destroy() if(defined($box));
my($ca, $t, $cn, $email, $cadir);
if(not defined($opts)) {
$cn = $main->{'certbrowser'}->selection_cn();
$email = $main->{'certbrowser'}->selection_email();
if(not defined $cn) {
GUI::HELPERS::print_info(_("Please select a Certificate first"));
return;
}
$ca = $main->{'certbrowser'}->selection_caname();
$cadir = $main->{'certbrowser'}->selection_cadir();
$opts->{'status'} = $main->{'certbrowser'}->selection_status();
$opts->{'cert'} = $main->{'certbrowser'}->selection_dn();
$opts->{'certname'} = HELPERS::enc_base64($opts->{'cert'});
$opts->{'certfile'} = $cadir."/certs/".$opts->{'certname'}.".pem";
$opts->{'keyfile'} = $cadir."/keys/".$opts->{'certname'}.".pem";
$opts->{'cafile'} = $cadir."/cacert.pem";
if (-f $cadir."/cachain.pem") {
$opts->{'cafile'} = $cadir."/cachain.pem";
}
if($opts->{'status'} ne _("VALID")) {
$t = _("Certificate seems not to be VALID");
$t .= "\n";
$t .= _("Export is not possible");
GUI::HELPERS::print_warning($t);
return;
}
$opts->{'parsed'} = $self->parse_cert($main, $opts->{'certname'});
if((defined($email)) && $email ne '' && $email ne ' ') {
$opts->{'outfile'} = "$main->{'exportdir'}/$email-cert.pem";
}elsif((defined($cn)) && $cn ne '' && $cn ne ' ') {
$opts->{'outfile'} = "$main->{'exportdir'}/$cn-cert.pem";
}else{
$opts->{'outfile'} = "$main->{'exportdir'}/cert.pem";
}
$opts->{'format'} = 'PEM';
$opts->{'include'} = 0;
$opts->{'incfp'} = 0;
$opts->{'nopass'} = 0;
$opts->{'friendlyname'} = '';
$main->show_export_dialog($opts, 'cert');
return;
}
if((not defined($opts->{'outfile'})) || ($opts->{'outfile'} eq '')) {
$main->show_export_dialog($opts, 'cert');
GUI::HELPERS::print_warning(
_("Please give at least the output file"));
return;
}
if($opts->{'format'} eq 'P12') {
if(not -s $opts->{'keyfile'}) {
$t = _("Key is necessary for export as PKCS#12");
$t .= "\n";
$t .= _("Export is not possible!");
GUI::HELPERS::print_warning($t);
return;
}
if((not defined($opts->{'p12passwd'})) &&
(not $opts->{'nopass'})) {
$opts->{'includeca'} = 1;
$main->show_p12_export_dialog($opts, 'cert');
return;
}
} elsif(($opts->{'format'} eq 'ZIP') || ($opts->{'format'} eq 'TAR')) {
if(not -s $opts->{'keyfile'}) {
$t = sprintf(
_("Key is necessary for export as %s"), $opts->{'format'});
$t .= "\n";
$t .= _("Export is not possible!");
GUI::HELPERS::print_warning($t);
return;
}
}
$self->export_cert($main, $opts); #FIXME no need for two functions
return;
}
#
# now really export the certificate
#
sub export_cert {
my ($self, $main, $opts) = @_;
my($ca, $t, $out, $ret, $ext);
GUI::HELPERS::set_cursor($main, 1);
$ca = $main->{'CA'}->{'actca'};
if($opts->{'format'} eq 'PEM') {
if($opts->{'incfp'}) {
$out = '';
$out .= "Fingerprint (MD5): $opts->{'parsed'}->{'FINGERPRINTMD5'}\n";
$out .= "Fingerprint (SHA1): $opts->{'parsed'}->{'FINGERPRINTSHA1'}\n\n";
} else {
$out = '';
}
$out .= $opts->{'parsed'}->{'PEM'};
if($opts->{'include'}) {
open(IN, "<$opts->{'keyfile'}") || do {
GUI::HELPERS::set_cursor($main, 0);
$t = sprintf(_("Can't open Certificate file: %s: %s"),
$opts->{'keyfile'}, $!);
return;
};
$out .= "\n";
$out .= $_ while(<IN>);
close(IN);
}
} elsif ($opts->{'format'} eq 'DER') {
$out = $opts->{'parsed'}->{'DER'};
} elsif ($opts->{'format'} eq 'TXT') {
$out = $opts->{'parsed'}->{'TEXT'};
} elsif ($opts->{'format'} eq 'P12') {
unlink($opts->{'outfile'});
($ret, $ext) = $self->{'OpenSSL'}->genp12(
certfile => $opts->{'certfile'},
keyfile => $opts->{'keyfile'},
cafile => $opts->{'cafile'},
outfile => $opts->{'outfile'},
passwd => $opts->{'passwd'},
p12passwd => $opts->{'p12passwd'},
includeca => $opts->{'includeca'},
nopass => $opts->{'nopass'},
friendly => $opts->{'friendlyname'}
);
GUI::HELPERS::set_cursor($main, 0);
if($ret eq 1) {
$t = "Wrong password given\nDecrypting Key failed\nGenerating PKCS#12 failed";
GUI::HELPERS::print_warning($t, $ext);
return;
} elsif($ret || (not -s $opts->{'outfile'})) {
$t = _("Generating PKCS#12 failed");
GUI::HELPERS::print_warning($t, $ext);
return;
}
$main->{'exportdir'} = HELPERS::write_export_dir($main,
$opts->{'outfile'});
$t = sprintf(_("Certificate and Key successfully exported to %s"),
$opts->{'outfile'});
GUI::HELPERS::print_info($t, $ext);
return;
} elsif (($opts->{'format'} eq "ZIP") || ($opts->{'format'} eq "TAR")) {
my $tmpcert = "$main->{'tmpdir'}/cert.pem";
my $tmpkey = "$main->{'tmpdir'}/key.pem";
my $tmpcacert = "$main->{'tmpdir'}/cacert.pem";
open(OUT, ">$tmpcert") || do {
GUI::HELPERS::set_cursor($main, 0);
$t = sprintf(_("Can't create temporary file: %s: %s"),
$tmpcert, $!);
GUI::HELPERS::print_warning($t);
return;
};
print OUT $opts->{'parsed'}->{'PEM'};
close OUT;
# store key in temporary location
{
open(IN, "<$opts->{'keyfile'}") || do {
GUI::HELPERS::set_cursor($main, 0);
$t = sprintf(_("Can't read Key file: %s: %s"), $tmpcert, $!);
GUI::HELPERS::print_warning($t);
return;
};
my @key = <IN>;
close IN;
open(OUT, ">$tmpkey") || do {
GUI::HELPERS::set_cursor($main, 0);
$t = sprintf(_("Can't create temporary file: %s: %s"),
$tmpcert, $!);
GUI::HELPERS::print_warning($t);
return;
};
print OUT @key;
close OUT;
}
# store cacert in temporary location
{
open(IN, "<$opts->{'cafile'}") || do {
GUI::HELPERS::set_cursor($main, 0);
GUI::HELPERS::print_warning(_("Can't read CA certificate"));
return;
};
my @cacert = <IN>;
close IN;
open(OUT, ">$tmpcacert") || do {
GUI::HELPERS::set_cursor($main, 0);
GUI::HELPERS::print_warning(_("Can't create temporary file"));
return;
};
print OUT @cacert;
close OUT;
}
unlink($opts->{'outfile'});
if($opts->{'format'} eq "ZIP") {
system($main->{'init'}->{'zipbin'}, '-j', $opts->{'outfile'},
$tmpcacert, $tmpkey, $tmpcert);
my $ret = $? >> 8;
} elsif ($opts->{'format'} eq "TAR") {
system($main->{'init'}->{'tarbin'}, 'cfv', $opts->{'outfile'},
$tmpcacert, $tmpkey, $tmpcert);
}
GUI::HELPERS::set_cursor($main, 0);
if(not -s $opts->{'outfile'} || $ret) {
GUI::HELPERS::print_warning(
sprintf(_("Generating %s file failed"), $opts->{'format'})
);
} else {
$main->{'exportdir'} = HELPERS::write_export_dir($main,
$opts->{'outfile'});
$t = sprintf(
_("Certificate and Key successfully exported to %s"),
$opts->{'outfile'});
GUI::HELPERS::print_info($t);
unlink($tmpcacert);
unlink($tmpcert);
unlink($tmpkey);
return;
}
} else {
GUI::HELPERS::set_cursor($main, 0);
$t = sprintf(_("Invalid Format for export_cert(): %s"),
$opts->{'format'});
GUI::HELPERS::print_warning($t);
return;
}
GUI::HELPERS::set_cursor($main, 0);
open(OUT, ">$opts->{'outfile'}") || do {
GUI::HELPERS::print_warning(_("Can't open output file: %s: %s"),
$opts->{'outfile'}, $!);
return;
};
print OUT $out;
close OUT;
$main->{'exportdir'} = HELPERS::write_export_dir($main,
$opts->{'outfile'});
$t = sprintf(_("Certificate successfully exported to: %s"),
$opts->{'outfile'});
GUI::HELPERS::print_info($t);
return;
}
sub reread_cert {
my ($self, $main, $name) = @_;
my ($parsed, $tmp);
GUI::HELPERS::set_cursor($main, 1);
$name = HELPERS::enc_base64($name);
$parsed = $self->parse_cert($main, $name, 1);
# print STDERR "DEBUG: status $parsed->{'STATUS'}\n";
foreach(@{$self->{'certlist'}}) {
if(/^$name%/) {
; #delete
} else {
push(@{$tmp}, $_);
}
}
push(@{$tmp}, $name."%".$parsed->{'STATUS'});
@{$tmp} = sort(@{$tmp});
delete($self->{'certlist'});
$self->{'certlist'} = $tmp;
GUI::HELPERS::set_cursor($main, 0);
return;
}
sub parse_cert {
my ($self, $main, $name, $force) = @_;
my($ca, $certfile, $x509, $parsed);
GUI::HELPERS::set_cursor($main, 1);
$ca = $main->{'CA'}->{'actca'};
if($name eq 'CA') {
$certfile = $main->{'CA'}->{$ca}->{'dir'}."/cacert.pem";
} else {
$certfile = $main->{'CA'}->{$ca}->{'dir'}."/certs/".$name.".pem";
}
$parsed = $self->{'OpenSSL'}->parsecert(
$main->{'CA'}->{$ca}->{'dir'}."/crl/crl.pem",
$main->{'CA'}->{$ca}->{'dir'}."/index.txt",
$certfile,
$force
);
GUI::HELPERS::set_cursor($main, 0);
return($parsed);
}
1

3105
lib/GUI.pm Normal file

File diff suppressed because it is too large Load Diff

173
lib/GUI/CALLBACK.pm Normal file
View File

@@ -0,0 +1,173 @@
# Copyright (c) Stephan Martin <sm@sm-zone.net>
#
# $Id: CALLBACK.pm,v 1.6 2006/06/28 21:50:42 sm Exp $
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
use strict;
package GUI::CALLBACK;
use POSIX;
#
# fill given var-reference with text from entry
#
sub entry_to_var {
my ($widget, $entry, $var, $box, $words) = @_;
if(defined($words)) {
$$var = $words->{$entry->get_text()};
}else{
$$var = $entry->get_text();
}
if(defined($box)) {
$box->{'button_ok'}->set_sensitive(1);
$box->{'button_apply'}->set_sensitive(1);
}
return;
}
#
# fill given var-reference with text from entry subjectAltName
# and set senitivity of togglebuttons
#
sub entry_to_var_san {
my ($widget, $entry, $var, $box, $words, $radio1, $radio2, $radio3, $radio4) = @_;
if(defined($words)) {
if(my $tmp = $words->{$entry->get_text()}) {
$$var = $tmp;
} else {
$$var = $entry->get_text();
}
#print STDERR "DEBUG: var: $$var\n";
if($$var eq 'user') {
#print STDERR "set sensitive(1)\n";
$radio1->set_sensitive(1) if(defined($radio1));
$radio2->set_sensitive(1) if(defined($radio2));
$radio3->set_sensitive(1) if(defined($radio3));
$radio4->set_sensitive(1) if(defined($radio4));
}else{
#print STDERR "DEBUG: set sensitive(0)\n";
#print STDERR "DEBUG: r1 $radio1 r2 $radio2 r3 $radio3 r4 $radio4\n";
$radio1->set_sensitive(0) if(defined($radio1));
$radio2->set_sensitive(0) if(defined($radio2));
$radio3->set_sensitive(0) if(defined($radio3));
$radio4->set_sensitive(0) if(defined($radio4));
}
}else{
$$var = $entry->get_text();
}
if(defined($box)) {
$box->{'button_ok'}->set_sensitive(1);
$box->{'button_apply'}->set_sensitive(1);
}
return;
}
#
# fill given var-reference with text from entry subjectAltName
# and set senitivity of togglebuttons
#
sub entry_to_var_key {
my ($widget, $entry, $var, $box, $words, $radio1, $radio2, $radio3) = @_;
if(defined($words)) {
if(my $tmp = $words->{$entry->get_text()}) {
$$var = $tmp;
} else {
$$var = $entry->get_text();
}
if(($$var ne '') && ($$var ne 'none')) {
$radio1->set_sensitive(1) if(defined($radio1));
$radio2->set_sensitive(1) if(defined($radio2));
$radio3->set_sensitive(1) if(defined($radio3));
}else{
$radio1->set_sensitive(0) if(defined($radio1));
$radio2->set_sensitive(0) if(defined($radio2));
$radio3->set_sensitive(0) if(defined($radio3));
}
}else{
$$var = $entry->get_text();
}
if(defined($box)) {
$box->{'button_ok'}->set_sensitive(1);
$box->{'button_apply'}->set_sensitive(1);
}
return;
}
#
# fill given var-reference with value from togglebutton
#
sub toggle_to_var {
my ($button, $var, $value, $outfileref, $formatref, $fileentry, $pass1,
$pass2) = @_;
$$var = $value;
if(defined($outfileref) && defined($formatref)) {
if($$outfileref =~ s/\.(pem|der|txt|p12|zip|tar)$//i) {
$$outfileref .= "." . lc $$formatref;
# something seem broken, need tmp var
my $tmp = $$outfileref;
$fileentry->set_text($tmp);
}
}
if(defined($pass1) && defined($pass2)) {
if($$formatref eq "PEM") {
$pass1->set_sensitive(1);
$pass2->set_sensitive(1);
} elsif ($$formatref eq "DER") {
$pass1->set_sensitive(0);
$pass2->set_sensitive(0);
} elsif ($$formatref eq "P12") {
$pass1->set_sensitive(0);
$pass2->set_sensitive(0);
} elsif ($$formatref eq "ZIP") {
$pass1->set_sensitive(0);
$pass2->set_sensitive(0);
} elsif ($$formatref eq "TAR") {
$pass1->set_sensitive(0);
$pass2->set_sensitive(0);
}
}
return;
}
#
# fill given var-reference with value from togglebutton
#
sub toggle_to_var_pref {
my ($button, $var, $value, $box) = @_;
$$var = $value;
if(defined($box) && defined($box->{'nb'}->get_current_page())) {
$box->{'button_ok'}->set_sensitive(1);
$box->{'button_apply'}->set_sensitive(1);
}
return;
}
1

479
lib/GUI/HELPERS.pm Normal file
View File

@@ -0,0 +1,479 @@
# Copyright (c) Stephan Martin <sm@sm-zone.net>
#
# $Id: HELPERS.pm,v 1.6 2006/06/28 21:50:42 sm Exp $
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
use strict;
package GUI::HELPERS;
use POSIX;
#
# Error message box, kills application
#
sub print_error {
my ($t, $ext) = @_;
my ($box, $button, $dbutton, $expander, $text, $scrolled, $buffer);
$button = Gtk2::Button->new_from_stock('gtk-ok');
$button->signal_connect('clicked', sub { HELPERS::exit_clean(1) });
$button->can_default(1);
$box = Gtk2::MessageDialog->new(
undef, [qw/destroy-with-parent modal/], 'error', 'none', $t);
$box->set_default_size(600, 0);
$box->set_resizable(1);
if(defined($ext)) {
$buffer = Gtk2::TextBuffer->new();
$buffer->set_text($ext);
$text = Gtk2::TextView->new_with_buffer($buffer);
$text->set_editable(0);
$text->set_wrap_mode('word');
$scrolled = Gtk2::ScrolledWindow->new(undef, undef);
$scrolled->set_policy('never', 'automatic');
$scrolled->set_shadow_type('etched-in');
$scrolled->add($text);
$expander = Gtk2::Expander->new(_("Command Details"));
$expander->add($scrolled);
$box->vbox->add($expander);
}
$box->add_action_widget($button, 0);
$box->show_all();
}
#
# Warning message box
#
sub print_warning {
my ($t, $ext) = @_;
my ($box, $button, $dbutton, $expander, $text, $scrolled, $buffer);
$button = Gtk2::Button->new_from_stock('gtk-ok');
$button->signal_connect('clicked', sub { $box->destroy() });
$button->can_default(1);
$box = Gtk2::MessageDialog->new(
undef, [qw/destroy-with-parent modal/], 'warning', 'none', $t);
$box->set_default_size(600, 0);
$box->set_resizable(1);
if(defined($ext)) {
$buffer = Gtk2::TextBuffer->new();
$buffer->set_text($ext);
$text = Gtk2::TextView->new_with_buffer($buffer);
$text->set_editable(0);
$text->set_wrap_mode('word');
$scrolled = Gtk2::ScrolledWindow->new(undef, undef);
$scrolled->set_policy('never', 'automatic');
$scrolled->set_shadow_type('etched-in');
$scrolled->add($text);
$expander = Gtk2::Expander->new(_("Command Details"));
$expander->add($scrolled);
$box->vbox->add($expander);
}
$box->add_action_widget($button, 0);
$box->show_all();
return;
}
#
# Info message box
#
sub print_info {
my ($t, $ext) = @_;
my ($box, $button, $dbutton, $buffer, $text, $scrolled, $expander);
$button = Gtk2::Button->new_from_stock('gtk-ok');
$button->signal_connect('clicked', sub { $box->destroy() });
$button->can_default(1);
$box = Gtk2::MessageDialog->new(
undef, [qw/destroy-with-parent modal/], 'info', 'none', $t);
$box->set_default_size(600, 0);
$box->set_resizable(1);
if(defined($ext)) {
$buffer = Gtk2::TextBuffer->new();
$buffer->set_text($ext);
$text = Gtk2::TextView->new_with_buffer($buffer);
$text->set_editable(0);
$text->set_wrap_mode('word');
$scrolled = Gtk2::ScrolledWindow->new(undef, undef);
$scrolled->set_policy('never', 'automatic');
$scrolled->set_shadow_type('etched-in');
$scrolled->add($text);
$expander = Gtk2::Expander->new(_("Command Details"));
$expander->add($scrolled);
$box->vbox->add($expander);
}
$box->add_action_widget($button, 0);
$box->show_all();
return;
}
#
# create standard dialog box
#
sub dialog_box {
my ($title, $text, $button1, $button2) = @_;
my $box = Gtk2::Dialog->new($title, undef, ["destroy-with-parent"]);
$box->add_action_widget($button1, 0);
if(defined($button2)) {
$box->add_action_widget($button2, 0);
$box->action_area->set_layout('spread');
}
if(defined($text)) {
my $label = create_label($text, 'center', 0, 1);
$box->vbox->pack_start($label, 0, 0, 0);
}
$box->signal_connect(response => sub { $box->destroy });
return($box);
}
#
# create standard label
#
sub create_label {
my ($text, $mode, $wrap, $bold) = @_;
$text = "<b>$text</b>" if($bold);
my $label = Gtk2::Label->new($text);
$label->set_justify($mode);
if($mode eq 'center') {
$label->set_alignment(0.5, 0.5);
}elsif($mode eq 'left') {
$label->set_alignment(0, 0);
}elsif($mode eq 'right') {
$label->set_alignment(1, 1);
}
$label->set_line_wrap($wrap);
$label->set_markup($text) if($bold);
return($label);
}
#
# write two labels to table
#
sub label_to_table {
my ($key, $val, $table, $row, $mode, $wrap, $bold) = @_;
my ($label, $entry);
$label = create_label($key, $mode, $wrap, $bold);
$label->set_padding(20, 0);
$table->attach_defaults($label, 0, 1, $row, $row+1);
$label = create_label($val, $mode, $wrap, $bold);
$label->set_padding(20, 0);
$table->attach_defaults($label, 1, 2, $row, $row+1);
$row++;
$table->resize($row, 2);
return($row);
}
#
# write label and entry to table
#
sub entry_to_table {
my ($text, $var, $table, $row, $visibility, $box) = @_;
my ($label, $entry);
$label = create_label($text, 'left', 0, 0);
$table->attach_defaults($label, 0, 1, $row, $row+1);
$entry = Gtk2::Entry->new();
$entry->set_text($$var) if(defined($$var));
$table->attach_defaults($entry, 1, 2, $row, $row+1);
$entry->signal_connect('changed' =>
sub {GUI::CALLBACK::entry_to_var($entry, $entry, $var, $box)} );
$entry->set_visibility($visibility);
return($entry);
}
#
# sort the table by the clicked column
#
sub sort_clist {
my ($clist, $col) = @_;
$clist->set_sort_column($col);
$clist->sort();
return(1);
}
sub create_activity_bar {
my ($t) = @_;
my($box, $bar);
$box = Gtk2::MessageDialog->new(
undef, [qw/destroy-with-parent modal/], 'info', 'none', $t);
$bar = Gtk2::ProgressBar->new();
$bar->pulse();
$bar->set_pulse_step(0.1);
$box->vbox->add($bar);
$box->show_all();
return($box, $bar);
}
#
# set curser busy
#
sub set_cursor {
my $main = shift;
my $busy = shift;
if($busy) {
$main->{'rootwin'}->set_cursor($main->{'busycursor'});
} else {
$main->{'rootwin'}->set_cursor($main->{'cursor'});
}
while(Gtk2->events_pending) {
Gtk2->main_iteration;
}
}
#
# call file chooser
#
sub browse_file {
my($title, $entry, $mode) = @_;
my($file_chooser, $filename, $filter);
$file_chooser = Gtk2::FileChooserDialog->new ($title, undef, $mode,
'gtk-cancel' => 'cancel',
'gtk-ok' => 'ok');
$file_chooser->add_shortcut_folder ('/tmp');
if($mode eq 'open') {
$filter = Gtk2::FileFilter->new();
$filter->set_name(_("Request Files (*.pem, *.der, *.req)"));
$filter->add_pattern("*.pem");
$filter->add_pattern("*.der");
$filter->add_pattern("*.req");
$file_chooser->add_filter($filter);
$filter = Gtk2::FileFilter->new();
$filter->set_name(_("All Files (*.*)"));
$filter->add_pattern("*");
$file_chooser->add_filter($filter);
}
if ('ok' eq $file_chooser->run) {
$filename = $file_chooser->get_filename();
$entry->set_text($filename);
}
$file_chooser->destroy();
}
#
# set text in statusbar
#
sub set_status {
my ($main, $t) = @_;
$main->{'bar'}->pop($main->{'lastid'}) if(defined($main->{'lastid'}));
$main->{'lastid'} = $main->{'bar'}->get_context_id('gargs');
$main->{'bar'}->push($main->{'lastid'}, $t);
}
1
__END__
=head1 NAME
GUI::HELPERS - helper functions for TinyCA, doing small jobs related to the
GUI
=head1 SYNOPSIS
use GUI::HELPERS;
GUI::HELPERS::print_info($text, $ext);
GUI::HELPERS::print_warning($text, $ext);
GUI::HELPERS::print_error($text, $ext);
GUI::HELPERS::sort_clist($clist, $col);
GUI::HELPERS::set_cursor($main, $busy);
GUI::HELPERS::browse_file($main, $entry, $mode);
GUI::HELPERS::set_status($main, $text);
$box = GUI::HELPERS::dialog_box(
$title, $text, $button1, $button2);
$label = GUI::HELPERS::create_label(
$text, $mode, $wrap, $bold);
$row = GUI::HELPERS::label_to_table(
$key, $val, $table, $row, $mode, $wrap, $bold);
$entry = GUI::HELPERS::entry_to_table(
$text, $var, $table, $row, $visibility, $box);
=head1 DESCRIPTION
GUI::HELPERS.pm is a library, containing some useful functions used by other
TinyCA2 modules. All functions are related to the GUI.
=head2 GUI::HELPERS::print_info($text, $ext);
=over 1
creates an Gtk2::MessageDialog of the type info. The string given in $text is
shown as message, the (multiline) string $ext is available through the
"Details" Button.
=back
=head2 GUI::HELPERS::print_warning($text, $ext);
=over 1
is identically with GUI::HELPERS::print_warning(), only the
Gtk2::MessageDialog is of type warning.
=back
=head2 GUI::HELPERS::print_error($text, $ext);
=over 1
is identically with GUI::HELPERS::print_info(), only the Gtk2::MessageDialogog
is of type error and the program will shut down after closing the message.
=back
=head2 GUI::HELPERS::sort_clist($clist, $col);
=over 1
sorts the clist with the values from the given column $col.
=back
=head2 GUI::HELPERS::dialog_box($title, $text, $button1, $button2);
=over 1
returns the reference to a new window of type Gtk2::Dialog. $title and
$button1 must be given. $text and $button2 are optional arguments and can be
undef.
=back
=head2 GUI::HELPERS::create_label($text, $mode, $wrap, $bold);
=over 1
returns the reference to a new Gtk2::Label. $mode can be "center", "left" or
"right". $wrap and $bold are boolean values.
=back
=head2 GUI::HELPERS::label_to_table($key, $val, $table, $row, $mode, $wrap, $bold);
=over 1
adds a new row to $table. The new row is appended at $row and has two columns:
the first will contain a label with the content of string $k, the second the
content of string $v. $mode, $wrap, $bold are the arguments for
GUI::HELPERS::create_label(), mentioned above.
The function returns the number of the next free row in the table.
=back
=head2 GUI::HELPERS::entry_to_table($text, $var, $table, $row, $visibility, $box);
=over 1
adds a new row to $table. The new row is appended at $row and has two columns:
the first will contain a label with the content of the string $text, the
second one will contain a textentry Gtk2::Entry, associated with the variable
$var. $visibility controls, if the entered text will be displayed or not
(passwords).
The function returns the reference to the new created entry.
=back
=head2 GUI::HELPERS::set_cursor($main, $busy);
=over 1
sets the actual cursor to busy or back to normal. The value of $busy is
boolean.
This functions returns nothing;
=back
=head2 GUI::HELPERS::browse_file($main, $entry, $mode);
=over 1
opens a FileChooser dialog to select files or directories. $entry is a
reference to the variable, where the selected path shall be stored. If $mode
is set to "open", then only files with appropriate suffixes are displyed.
=back
=head2 GUI::HELPERS::set_status($main, $text);
=over 1
sets the text in $text to the statusbar at the bottom of the window.
=back
=cut

1502
lib/GUI/TCONFIG.pm Normal file

File diff suppressed because it is too large Load Diff

112
lib/GUI/WORDS.pm Normal file
View File

@@ -0,0 +1,112 @@
# Copyright (c) Stephan Martin <sm@sm-zone.net>
#
# $Id: WORDS.pm,v 1.2 2006/06/28 21:50:42 sm Exp $
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
use strict;
package GUI::WORDS;
sub new {
my $that = shift;
my $self = {
'none' => _("Not set"),
'user' => _("Ask User"),
'critical' => _("critical"),
'noncritical' => _("not critical"),
'emailcopy' => _("Copy Email"),
'raw' => _("raw"),
'dns' => _("DNS Name"),
'ip' => _("IP Address"),
'mail' => _("Email"),
'server' => _("SSL Server"),
'server, client' => _("SSL Server, SSL Client"),
'key' => _("Key Encipherment"),
'sig' => _("Digital Signature"),
'keysig' => _("Key Encipherment, Digital Signature"),
'objsign' => _("Object Signing"),
'client, objsign' => _("SSL Client, Object Signing"),
'client, email' => _("SSL Client, Email(S/MIME)"),
'client' => _("SSL Client"),
'email' => _("Email(S/MIME)"),
'client, email, objsign'=> _("SSL Client, Email, Object Signing"),
'objCA' => _("Object Signing CA"),
'emailCA' => _("S/MIME CA"),
'sslCA' => _("SSL CA"),
'sslCA, emailCA' => _("SSL CA, S/MIME CA"),
'sslCA, objCA' => _("SSL CA, Object Signing CA"),
'emailCA, objCA' => _("S/MIME CA, Object Signing CA"),
'sslCA, emailCA, objCA' => _("SSL CA, S/MIME CA, Object Signing CA"),
'keyCertSign' => _("Certificate Signing"),
'cRLSign' => _("CRL Signing"),
'keyCertSign, cRLSign' => _("Certificate Signing, CRL Signing"),
'CN' => _("Common Name"),
'EMAIL' => _("eMail Address"),
'O' => _("Organization"),
'OU' => _("Organizational Unit"),
'L' => _("Location"),
'ST' => _("State"),
'C' => _("Country"),
'NOTBEFORE' => _("Creation Date"),
'NOTAFTER' => _("Expiration Date"),
'KEYSIZE' => _("Keylength"),
'PK_ALGORITHM' => _("Public Key Algorithm"),
'SIG_ALGORITHM' => _("Signature Algorithm"),
'TYPE' => _("Type"),
'SERIAL' => _("Serial"),
'STATUS' => _("Status"),
'FINGERPRINTMD5' => _("Fingerprint (MD5)"),
'FINGERPRINTSHA1' => _("Fingerprint (SHA1)"),
_("Not set") => 'none',
_("Ask User") => 'user',
_("critical") => 'critical',
_("not critical") => 'noncritical',
_("Copy Email") => 'emailcopy',
_("raw") => 'raw',
_("DNS Name") => 'dns',
_("Email") => 'email',
_("IP Address") => 'ip',
_("SSL Server") => 'server',
_("SSL Server, SSL Client") => 'server, client',
_("Key Encipherment") => 'key',
_("Digital Signature") => 'sig',
_("Key Encipherment, Digital Signature") => 'keysig',
_("Object Signing") => 'objsign',
_("Email(S/MIME)") => 'email',
_("SSL Client, Email(S/MIME)") => 'client, email',
_("SSL Client") => 'client',
_("SSL Client, Object Signing") => 'client, objsign',
_("SSL Client, Email, Object Signing") => 'client, email, objsign',
_("Object Signing CA") => 'objCA',
_("S/MIME CA") => 'emailCA',
_("SSL CA") => 'sslCA',
_("SSL CA, S/MIME CA") => 'sslCA, emailCA',
_("SSL CA, Object Signing CA") => 'sslCA, objCA',
_("S/MIME CA, Object Signing CA") => 'emailCA, objCA',
_("SSL CA, S/MIME CA, Object Signing CA")=> 'sslCA, emailCA, objCA',
_("Certificate Signing") => 'keyCertSign',
_("CRL Signing") => 'cRLSign',
_("Certificate Signing, CRL Signing") => 'keyCertSign, cRLSign'
};
my $class = ref($that) || $that;
bless($self, $class);
$self;
}
1

879
lib/GUI/X509_browser.pm Normal file
View File

@@ -0,0 +1,879 @@
# Copyright (c) Olaf Gellert <og@pre-secure.de> and
# Stephan Martin <sm@sm-zone.net>
#
# $Id: X509_browser.pm,v 1.6 2006/06/28 21:50:42 sm Exp $
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
use strict;
package GUI::X509_browser;
use HELPERS;
use GUI::HELPERS;
use GUI::X509_infobox;
use POSIX;
my $tmpdefault="/tmp";
my $version = "0.1";
my $true = 1;
my $false = undef;
sub new {
my $that = shift;
my $self = {};
$self->{'main'} = shift;
my $mode = shift;
my ($font, $fontfix);
my $class = ref($that) || $that;
if ((defined $mode) &&
(($mode eq 'cert') || ($mode eq 'req') || ($mode eq 'key'))) {
$self->{'mode'} = $mode;
} else {
printf STDERR "No mode specified for X509browser\n";
return undef;
}
# initialize fonts and styles
$font = Gtk2::Pango::FontDescription->from_string(
"-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*");
if(defined($font)) {
$self->{'stylebold'} = Gtk2::Style->new();
$self->{'stylebold'}->font_desc->from_string(
"-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*");
} else {
$self->{'stylebold'} = undef;
}
$fontfix = Gtk2::Pango::FontDescription->from_string(
"-adobe-courier-medium-r-normal--*-100-*-*-*-*-*-*");
if(defined($fontfix)) {
$self->{'stylefix'} = Gtk2::Style->new();
$self->{'stylefix'}->font_desc->from_string(
"-adobe-courier-medium-r-normal--*-100-*-*-*-*-*-*");
} else {
$self->{'stylefix'} = undef;
}
bless($self, $class);
$self;
}
# sub create_window {
# my ($self, $title, $ok_text, $cancel_text,
# $ok_function, $cancel_function) = @_;
#
# my ($button_ok, $button_cancel);
#
# if ( $self->{'dialog_shown'} == $true ) {
# return(undef);
# }
#
# # check arguments
# if ($title eq undef) {
# $title = "CA browser, V$version";
# }
#
# if (not defined($ok_text)) {
# $ok_text = _("OK");
# }
# if (not defined($cancel_text)) {
# $cancel_text = _("Cancel");
# }
#
# # initialize main window
# $self->{'window'} = new Gtk::Dialog();
#
# # $self->{'window'}->set_policy($false,$false,$true);
#
# # store pointer to vbox as "browser widget"
# $self->{'browser'}=$self->{'window'}->vbox;
#
# if (defined $ok_function) {
# # todo: we should check if this is a function reference
# $self->{'User_OK_function'} = $ok_function;
# }
# $self->{'OK_function'} = sub { $self->ok_function(); };
#
# if (defined $cancel_function) {
# # todo: we should check if this is a function reference
# $self->{'User_CANCEL_function'} = $cancel_function;
# }
# $self->{'CANCEL_function'} = sub { $self->cancel_function(); };
#
#
#
# $button_ok = new Gtk::Button( "$ok_text" );
# $button_ok->signal_connect( "clicked", $self->{'OK_function'});
# $self->{'window'}->action_area->pack_start( $button_ok, $true, $true, 0 );
#
# $button_cancel = new Gtk::Button( "$cancel_text" );
# $button_cancel->signal_connect('clicked', $self->{'CANCEL_function'});
# $self->{'window'}->action_area->pack_start( $button_cancel, $true, $true, 0 );
#
# $self->{'window'}->set_title( "$title" );
#
# $self->{'window'}->show_all();
#
# }
sub set_window {
my $self = shift;
my $widget = shift;
if ( (not defined $self->{'browser'}) || ( $self->{'browser'} == undef )) {
$self->{'browser'}=$widget;
} else {
# browser widget already exists
return $false;
}
}
sub add_list {
my ($self, $actca, $directory, $crlfile, $indexfile) = @_;
my ($x509listwin, @titles, @certtitles, @reqtitles, @keytitles, $column,
$color, $text, $iter, $renderer);
# printf STDERR "AddList: Self: $self, Dir $directory, CRL $crlfile, Index: $indexfile\n";
@reqtitles = (_("Common Name"),
_("eMail Address"),
_("Organizational Unit"),
_("Organization"),
_("Location"),
_("State"),
_("Country"));
@certtitles = (_("Common Name"),
_("eMail Address"),
_("Organizational Unit"),
_("Organization"),
_("Location"),
_("State"),
_("Country"),
_("Status"));
@keytitles = (_("Common Name"),
_("eMail Address"),
_("Organizational Unit"),
_("Organization"),
_("Location"),
_("State"),
_("Country"),
_("Type"));
$self->{'actca'} = $actca;
$self->{'actdir'} = $directory;
$self->{'actcrl'} = $crlfile;
$self->{'actindex'} = $indexfile;
if(defined($self->{'x509box'})) {
$self->{'browser'}->remove($self->{'x509box'});
$self->{'x509box'}->destroy();
}
$self->{'x509box'} = Gtk2::VBox->new(0, 0);
# pane for list (top) and cert infos (bottom)
$self->{'x509pane'} = Gtk2::VPaned->new();
$self->{'x509pane'}->set_position(250);
$self->{'x509box'}->add($self->{'x509pane'});
$self->{'browser'}->pack_start($self->{'x509box'}, 1, 1, 0);
# now the list
$x509listwin = Gtk2::ScrolledWindow->new(undef, undef);
$x509listwin->set_policy('automatic', 'automatic');
$x509listwin->set_shadow_type('etched-in');
$self->{'x509pane'}->pack1($x509listwin, 1, 1);
# shall we display certificates, requests or keys?
if ((defined $self->{'mode'}) && ($self->{'mode'} eq "cert")) {
$self->{'x509store'} = Gtk2::ListStore->new(
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::Int');
@titles = @certtitles;
} elsif ((defined $self->{'mode'}) && ($self->{'mode'} eq "req")) {
$self->{'x509store'} = Gtk2::ListStore->new(
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::Int');
@titles = @reqtitles;
} elsif ((defined $self->{'mode'}) && ($self->{'mode'} eq "key")) {
$self->{'x509store'} = Gtk2::ListStore->new(
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::String',
'Glib::Int');
@titles = @keytitles;
} else {
# undefined mode
return undef;
}
$self->{'x509store'}->set_sort_column_id(0, 'ascending');
$self->{'x509clist'} = Gtk2::TreeView->new_with_model($self->{'x509store'});
$self->{'x509clist'}->get_selection->set_mode ('single');
for(my $i = 0; $titles[$i]; $i++) {
$renderer = Gtk2::CellRendererText->new();
$column = Gtk2::TreeViewColumn->new_with_attributes(
$titles[$i], $renderer, 'text' => $i);
$column->set_sort_column_id($i);
$column->set_resizable(1);
if (($i == 7) && ($self->{'mode'} eq 'cert')) {
$column->set_cell_data_func ($renderer, sub {
my ($column, $cell, $model, $iter) = @_;
$text = $model->get($iter, 7);
$color = $text eq _("VALID")?'green':'red';
$cell->set (text => $text, foreground => $color);
});
}
$self->{'x509clist'}->append_column($column);
}
if ((defined $self->{'mode'}) && ($self->{'mode'} eq 'cert')) {
$self->{'x509clist'}->get_selection->signal_connect('changed' =>
sub { _fill_info($self, 'cert') });
} elsif ((defined $self->{'mode'}) && ($self->{'mode'} eq 'req')) {
$self->{'x509clist'}->get_selection->signal_connect('changed' =>
sub { _fill_info($self, 'req') });
}
$x509listwin->add($self->{'x509clist'});
update($self, $directory, $crlfile, $indexfile, $true);
}
sub update {
my ($self, $directory, $crlfile, $indexfile, $force) = @_;
$self->{'actdir'} = $directory;
$self->{'actcrl'} = $crlfile;
$self->{'actindex'} = $indexfile;
# print STDERR "DEBUG: set new dir: $self->{'actdir'}\n";
if ($self->{'mode'} eq "cert") {
update_cert($self, $directory, $crlfile, $indexfile, $force);
} elsif ($self->{'mode'} eq "req") {
update_req($self, $directory, $crlfile, $indexfile, $force);
} elsif ($self->{'mode'} eq "key") {
update_key($self, $directory, $crlfile, $indexfile, $force);
} else {
return undef;
}
if ((defined $self->{'infowin'}) && ($self->{'infowin'} ne "")) {
update_info($self);
}
$self->{'browser'}->show_all();
return($true);
}
sub update_req {
my ($self, $directory, $crlfile, $indexfile, $force) = @_;
my ($ind, $name, $state, @line, $iter);
$self->{'main'}->{'REQ'}->read_reqlist(
$directory, $crlfile, $indexfile, $force, $self->{'main'});
$self->{'x509store'}->clear();
$ind = 0;
foreach my $n (@{$self->{'main'}->{'REQ'}->{'reqlist'}}) {
($name, $state) = split(/\%/, $n);
@line = split(/\:/, $name);
$iter = $self->{'x509store'}->append();
$self->{'x509store'}->set($iter,
0 => $line[0],
1 => $line[1],
2 => $line[2],
3 => $line[3],
4 => $line[4],
5 => $line[5],
6 => $line[6],
7 => $ind);
$ind++;
}
# now select the first row to display certificate informations
$self->{'x509clist'}->get_selection->select_path(
Gtk2::TreePath->new_first());
}
sub update_cert {
my ($self, $directory, $crlfile, $indexfile, $force) = @_;
my ($ind, $name, $state, @line, $iter);
$self->{'main'}->{'CERT'}->read_certlist(
$directory, $crlfile, $indexfile, $force, $self->{'main'});
$self->{'x509store'}->clear();
$ind = 0;
foreach my $n (@{$self->{'main'}->{'CERT'}->{'certlist'}}) {
($name, $state) = split(/\%/, $n);
@line = split(/\:/, $name);
$iter = $self->{'x509store'}->append();
$self->{'x509store'}->set($iter,
0 => $line[0],
1 => $line[1],
2 => $line[2],
3 => $line[3],
4 => $line[4],
5 => $line[5],
6 => $line[6],
7 => $state,
8 => $ind);
# $self->{'x509clist'}->set_text($row, 7, $state);
# if($state eq _("VALID")) {
# $self->{'x509clist'}->set_cell_style($row, 7, $self->{'stylegreen'});
# } else {
# $self->{'x509clist'}->set_cell_style($row, 7, $self->{'stylered'});
# }
# $self->{'x509clist'}->set_text($row, 8, $ind);
$ind++;
}
# now select the first row to display certificate informations
$self->{'x509clist'}->get_selection->select_path(
Gtk2::TreePath->new_first());
}
sub update_key {
my ($self, $directory, $crlfile, $indexfile, $force) = @_;
my ($ind, $name, @line, $iter, $state);
$self->{'main'}->{'KEY'}->read_keylist($self->{'main'});
$self->{'x509store'}->clear();
$ind = 0;
foreach my $n (@{$self->{'main'}->{'KEY'}->{'keylist'}}) {
($name, $state) = split(/\%/, $n);
@line = split(/\:/, $name);
$iter = $self->{'x509store'}->append();
$self->{'x509store'}->set($iter,
0 => $line[0],
1 => $line[1],
2 => $line[2],
3 => $line[3],
4 => $line[4],
5 => $line[5],
6 => $line[6],
7 => $state,
8 => $ind);
# $self->{'x509clist'}->set_text($row, 7, $state);
# if($state eq _("VALID")) {
# $self->{'x509clist'}->set_cell_style($row, 7, $self->{'stylegreen'});
# } else {
# $self->{'x509clist'}->set_cell_style($row, 7, $self->{'stylered'});
# }
# $self->{'x509clist'}->set_text($row, 8, $ind);
$ind++;
}
}
sub update_info {
my ($self)=@_;
my ($title, $parsed, $dn);
$dn = selection_dn($self);
if (defined $dn) {
$dn = HELPERS::enc_base64($dn);
if ($self->{'mode'} eq 'cert') {
$parsed = $self->{'main'}->{'CERT'}->parse_cert($self->{'main'},
$dn, $false);
$title = _("Certificate Information");
} else {
$parsed = $self->{'main'}->{'REQ'}->parse_req($self->{'main'}, $dn,
$false);
$title = _("Request Information");
}
defined($parsed) ||
GUI::HELPERS::print_error(_("Can't read file"));
if(not defined($self->{'infobox'})) {
$self->{'infobox'} = Gtk2::VBox->new();
}
# printf STDERR "DEBUG: Infowin: $self->{'infowin'}, infobox: $self->{'infobox'}\n";
$self->{'infowin'}->display($self->{'infobox'}, $parsed,
$self->{'mode'}, $title);
} else {
# nothing selected
$self->{'infowin'}->hide();
}
}
#
# add infobox to the browser window
#
sub add_info {
my $self = shift;
my ($row, $index, $parsed, $title, $status, $list, $dn);
if ((defined $self->{'infowin'}) && ($self->{'infowin'} ne "")) {
$self->{'infowin'}->hide();
} else {
$self->{'infowin'} = GUI::X509_infobox->new();
}
# printf STDERR "Infowin: $self->{'infowin'}\n";
# printf STDERR "x509clist: $self->{'x509clist'}\n";
$row = $self->{'x509clist'}->get_selection->get_selected();
if(defined($row)) {
if ($self->{'mode'} eq 'cert') {
$index = ($self->{'x509store'}->get($row))[8];
$list = $self->{'main'}->{'CERT'}->{'certlist'};
} else {
$index = ($self->{'x509store'}->get($row))[7];
$list = $self->{'main'}->{'REQ'}->{'reqlist'};
}
}
if (defined $index) {
($dn, $status) = split(/\%/, $list->[$index]);
$dn = HELPERS::enc_base64($dn);
if ($self->{'mode'} eq 'cert') {
$parsed = $self->{'main'}->{'CERT'}->parse_cert($self->{'main'}, $dn,
$false);
$title="Certificate Information";
} else {
$parsed = $self->{'main'}->{'REQ'}->parse_req($self->{'main'}, $dn,
$false);
$title="Request Information";
}
defined($parsed) || GUI::HELPERS::print_error(_("Can't read file"));
# printf STDERR "Infowin: $self->{'infowin'}\n";
$self->{'infobox'} = Gtk2::VBox->new();
$self->{'x509pane'}->pack2($self->{'infobox'}, 1, 1);
$self->{'infowin'}->display($self->{'infobox'}, $parsed, $self->{'mode'},
$title);
}
}
sub hide {
my ($self) = @_;
$self->{'window'}->hide();
$self->{'dialog_shown'} = $false;
}
sub destroy {
my ($self) = @_;
$self->{'window'}->destroy();
$self->{'dialog_shown'} = $false;
}
#
# signal handler for selected list items
# (updates the X509_infobox window)
# XXX why is that function needed??
#
sub _fill_info {
my ($self) = @_;
# print STDERR "DEBUG: fill_info: @_\n";
update_info($self) if (defined $self->{'infowin'});
}
sub selection_fname {
my $self = shift;
my ($selected, $row, $index, $dn, $status, $filename, $list);
$row = $self->{'x509clist'}->get_selection->get_selected();
return undef if (not defined $row);
if ($self->{'mode'} eq 'req') {
$index = ($self->{'x509store'}->get($row))[7];
$list = $self->{'main'}->{'REQ'}->{'reqlist'};
} elsif ($self->{'mode'} eq 'cert') {
$index = ($self->{'x509store'}->get($row))[8];
$list = $self->{'main'}->{'CERT'}->{'certlist'};
} elsif ($self->{'mode'} eq 'key') {
$index = ($self->{'x509store'}->get($row))[8];
$list = $self->{'main'}->{'KEY'}->{'certlist'};
} else {
GUI::HELPERS::print_error(
_("Invalid browser mode for selection_fname():"." "
.$self->{'mode'}));
}
if (defined $index) {
($dn, $status) = split(/\%/, $list->[$index]);
$filename= HELPERS::enc_base64($dn);
$filename=$self->{'actdir'}."/$filename".".pem";
} else {
$filename = undef;
}
return($filename);
}
sub selection_dn {
my $self = shift;
my ($selected, $row, $index, $dn, $status, $list);
$row = $self->{'x509clist'}->get_selection->get_selected();
return undef if (not defined $row);
if ($self->{'mode'} eq 'req') {
$index = ($self->{'x509store'}->get($row))[7];
$list = $self->{'main'}->{'REQ'}->{'reqlist'};
} elsif ($self->{'mode'} eq 'cert') {
$index = ($self->{'x509store'}->get($row))[8];
$list = $self->{'main'}->{'CERT'}->{'certlist'};
} elsif ($self->{'mode'} eq 'key') {
$index = ($self->{'x509store'}->get($row))[8];
$list = $self->{'main'}->{'KEY'}->{'keylist'};
} else {
GUI::HELPERS::print_error(
_("Invalid browser mode for selection_dn():"." "
.$self->{'mode'}));
}
if (defined $index) {
($dn, $status) = split(/\%/, $list->[$index]);
} else {
$dn = undef;
}
return($dn);
}
sub selection_cadir {
my $self = shift;
my $dir;
$dir = $self->{'actdir'};
# cut off the last directory name to provide the ca-directory
$dir =~ s/\/certs|\/req|\/keys$//;
return($dir);
}
sub selection_caname {
my $self = shift;
my ($selected, $caname);
$caname = $self->{'actca'};
return($caname);
}
sub selection_cn {
my $self = shift;
my ($selected, $row, $index, $cn);
$row = $self->{'x509clist'}->get_selection->get_selected();
return undef if (not defined $row);
if (($self->{'mode'} eq 'req') ||
($self->{'mode'} eq 'cert')||
($self->{'mode'} eq 'key')) {
$cn = ($self->{'x509store'}->get($row))[0];
} else {
GUI::HELPERS::print_error(
_("Invalid browser mode for selection_cn():"." "
.$self->{'mode'}));
}
return($cn);
}
sub selection_email {
my $self = shift;
my ($selected, $row, $index, $email);
$row = $self->{'x509clist'}->get_selection->get_selected();
return undef if (not defined $row);
if (($self->{'mode'} eq 'req') ||
($self->{'mode'} eq 'cert') ||
($self->{'mode'} eq 'key')) {
$email = ($self->{'x509store'}->get($row))[1];
} else {
GUI::HELPERS::print_error(
_("Invalid browser mode for selection_cn():"." "
.$self->{'mode'}));
}
return($email);
}
sub selection_status {
my $self = shift;
my ($selected, $row, $index, $dn, $status, $list);
$row = $self->{'x509clist'}->get_selection->get_selected();
return undef if (not defined $row);
if ($self->{'mode'} eq 'cert') {
$index = ($self->{'x509store'}->get($row))[8];
$list = $self->{'main'}->{'CERT'}->{'certlist'};
} else {
GUI::HELPERS::print_error(
_("Invalid browser mode for selection_status():"." "
.$self->{'mode'}));
}
if (defined $index) {
($dn, $status) = split(/\%/, $list->[$index]);
} else {
$status = undef;
}
return($status);
}
sub selection_type {
my $self = shift;
my ($selected, $row, $index, $dn, $type, $list);
$row = $self->{'x509clist'}->get_selection->get_selected();
return undef if (not defined $row);
if ($self->{'mode'} eq 'key') {
$index = ($self->{'x509store'}->get($row))[8];
$list = $self->{'main'}->{'KEY'}->{'keylist'};
} else {
GUI::HELPERS::print_error(
_("Invalid browser mode for selection_type():"." "
.$self->{'mode'}));
}
if (defined $index) {
($dn, $type) = split(/\%/, $list->[$index]);
} else {
$type = undef;
}
return($type);
}
sub ok_function {
my ($self) = @_;
# is there a user defined ok_function?
if (defined $self->{'User_OK_function'}) {
$self->{'User_OK_function'}($self, selection_fname($self));
}
# otherwise do default
else {
printf STDOUT "%s\n", selection_fname($self);
$self->hide();
}
return $true;
}
sub cancel_function {
my ($self) = @_;
# is there a user defined ok_function?
if (defined $self->{'User_CANCEL_function'}) {
$self->{'User_CANCEL_function'}($self, get_listselect($self));
}
# otherwise do default
else {
$self->{'window'}->hide();
$self->{'dialog_shown'} = $false;
}
return $true;
}
#
# sort the table by the clicked column
#
sub _sort_clist {
my ($clist, $col) = @_;
$clist->set_sort_column($col);
$clist->sort();
return(1);
}
#
# called on mouseclick in certlist
#
sub _show_cert_menu {
my ($clist, $self, $event) = @_;
if ((defined($event->{'type'})) &&
$event->{'button'} == 3) {
$self->{'certmenu'}->popup(
undef,
undef,
0,
$event->{'button'},
undef);
return(1);
}
return(0);
}
$true;
__END__
=head1 NAME
GUI::X509_browser - Perl-Gtk2 browser for X.509 certificates and requests
=head1 SYNOPSIS
use X509_browser;
$browser=X509_browser->new($mode);
$browser->create_window($title, $oktext, $canceltext,
\&okayfunction, \&cancelfunction);
$browser->add_ca_select($cadir, @calist, $active-ca);
$browser->add_list($active-ca, $X509dir, $crlfile, $indexfile);
$browser->add_info();
my $selection = $browser->selection_fname();
$browser->hide();
=head1 DESCRIPTION
This displays a browser for X.509v3 certificates or certification
requests (CSR) from a CA managed by TinyCA2 (or some similar
structure).
Creation of an X509_browser is done by calling B<new()>,
the argument has to be 'cert' or 'req' to display certificates
or requests.
A window can be created for this purpose using
B<create_window($title, $oktext, $canceltext, \&okfunction, \&cancelfunction)>,
all arguments are optional.
=over 1
=item $title:
the existing Gtk2::VBox inside which the info will be
displayed.
=item $oktext:
The text to be displayed on the OK button of the dialog.
=item $canceltext:
The text to be displayed on the CANCEL button of the dialog.
=item \&okfunction:
Reference to a function that is executed on click on OK button.
This function should fetch the selected result (using
B<selection_fname()>) and also close the dialog using B<hide()>.
=item \&cancelfunction:
Reference to a function that is executed on click on CANCEL button.
This function should also close the dialog using B<hide()>.
=back
Further functions to get information about the selected item
exist, these are <B>selection_dn()</B>, <B>selection_status()</B>,
<B>selection_cadir()</B> and <B>selection_caname()</B>.
An existing infobox that already displays the content
of some directory can be modified by calling
<B>update()</B> with the same arguments that add_list().
An existing infobox is destroyed by calling B<destroy()>.
=cut

280
lib/GUI/X509_infobox.pm Normal file
View File

@@ -0,0 +1,280 @@
# Copyright (c) Olaf Gellert <og@pre-secure.de> and
# Stephan Martin <sm@sm-zone.net>
#
# $Id: X509_infobox.pm,v 1.7 2006/06/28 21:50:42 sm Exp $
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
use strict;
package GUI::X509_infobox;
use HELPERS;
use GUI::HELPERS;
use GUI::WORDS;
use POSIX;
my $version = "0.1";
my $true = 1;
my $false = undef;
sub new {
my $that = shift;
my $self = {};
my $class = ref($that) || $that;
$self->{'init'} = shift;
bless($self, $class);
$self;
}
sub display {
my ($self, $parent, $parsed, $mode, $title) = @_;
my ($bottombox, $textbox, $lefttable, $righttable, $leftbox, $rightbox,
@fields, $scrolled);
$self->{'root'} = $parent;
if (defined $self->{'child'}) {
$self->{'child'}->destroy();
}
# if title is given create a surrounding frame with the title
if (defined $title) {
$self->{'child'}= Gtk2::Frame->new($title);
$self->{'x509textbox'}= Gtk2::VBox->new(0,0);
$self->{'child'}->add($self->{'x509textbox'});
}
# otherwise we create the VBox directly inside the root widget
else {
$self->{'child'} = Gtk2::VBox->new(0,0);
$self->{'x509textbox'} = $self->{'child'};
}
# and pack it there
$self->{'root'}->pack_start($self->{'child'}, 1, 1, 0);
if (($mode eq 'cert') || ($mode eq 'cacert')) {
# fingerprint in the top of certtextbox
if(defined($self->{'certfingerprintmd5'})) {
$self->{'certfingerprintmd5'}->destroy();
}
$self->{'certfingerprintmd5'} = GUI::HELPERS::create_label(
_("Fingerprint (MD5)").": ".$parsed->{'FINGERPRINTMD5'},
'center', 0, 0);
$self->{'x509textbox'}->pack_start( $self->{'certfingerprintmd5'},
0, 0, 0);
if(defined($self->{'certfingerprintsha1'})) {
$self->{'certfingerprintsha1'}->destroy();
}
$self->{'certfingerprintsha1'} = GUI::HELPERS::create_label(
_("Fingerprint (SHA1)").": ".$parsed->{'FINGERPRINTSHA1'},
'center', 0, 0);
$self->{'x509textbox'}->pack_start($self->{'certfingerprintsha1'},
0, 0, 0);
}
if (($mode eq 'cert') || ($mode eq 'cacert')) {
$bottombox = 'certbottombox';
$textbox = 'x509textbox';
$lefttable = 'certlefttable';
$leftbox = 'certleftbox';
$righttable = 'certrighttable';
$rightbox = 'certrightbox';
}else{
$bottombox = 'reqbottombox';
$textbox = 'x509textbox';
$lefttable = 'reqlefttable';
$leftbox = 'reqleftbox';
$righttable = 'reqrighttable';
$rightbox = 'reqrightbox';
}
# hbox in the bottom
if(defined($self->{$bottombox})) {
$self->{$bottombox}->destroy();
}
$self->{$bottombox} = Gtk2::HBox->new(1, 0);
$self->{$textbox}->pack_start($self->{$bottombox}, 1, 1, 5);
# vbox in the bottom/left
if(defined($self->{$lefttable})) {
$self->{$lefttable}->destroy();
}
@fields = qw( CN EMAIL O OU L ST C);
$self->{$lefttable} = _create_detail_table(\@fields, $parsed);
# the only widget i know to set shadow type :-(
$scrolled = Gtk2::ScrolledWindow->new();
$scrolled->set_shadow_type('etched-in');
$scrolled->set_policy('never', 'never');
$self->{$leftbox} = Gtk2::VBox->new(0, 0);
$self->{$bottombox}->pack_start($self->{$leftbox}, 1, 1, 0);
$self->{$leftbox}->pack_start($scrolled, 1, 1, 0);
$scrolled->add($self->{$lefttable});
# vbox in the bottom/right
if(defined($self->{$righttable})) {
$self->{$righttable}->destroy();
}
if ($mode eq "cacert") {
@fields = qw(SERIAL NOTBEFORE NOTAFTER KEYSIZE PK_ALGORITHM SIG_ALGORITHM
TYPE);
} else {
@fields = qw(STATUS SERIAL NOTBEFORE NOTAFTER KEYSIZE PK_ALGORITHM
SIG_ALGORITHM TYPE);
}
$self->{$righttable} = _create_detail_table(\@fields, $parsed);
$scrolled = Gtk2::ScrolledWindow->new();
$scrolled->set_shadow_type('etched-in');
$scrolled->set_policy('never', 'never');
$self->{$rightbox} = Gtk2::VBox->new(0, 0);
$self->{$bottombox}->pack_start($self->{$rightbox}, 1, 1, 0);
$self->{$rightbox}->pack_start($scrolled, 1, 1, 0);
$scrolled->add($self->{$righttable});
$self->{$textbox}->show_all();
$parent->show_all();
}
sub hide {
my $self = shift;
if (defined $self->{'child'}) {
$self->{'child'}->destroy();
undef $self->{'child'};
}
}
#
# create standard table with details (cert/req)
#
sub _create_detail_table {
my ($fields, $parsed) = @_;
my ($list, $store, $rows, $words, @l, $iter, $column, $renderer);
$words = GUI::WORDS->new();
$store = Gtk2::ListStore->new('Glib::String', 'Glib::String');
$list = Gtk2::TreeView->new_with_model($store);
$list->set_headers_visible(0);
$list->get_selection->set_mode('none');
$renderer = Gtk2::CellRendererText->new();
$column = Gtk2::TreeViewColumn->new_with_attributes(
'', $renderer, 'text' => 0);
$list->append_column($column);
$renderer = Gtk2::CellRendererText->new();
$column = Gtk2::TreeViewColumn->new_with_attributes(
'', $renderer, 'text' => 1);
$list->append_column($column);
foreach my $f (@{$fields}) {
if(defined($parsed->{$f})){
if(ref($parsed->{$f})) {
foreach(@{$parsed->{$f}}) {
$iter = $store->append();
$store->set($iter, 0 => $words->{$f}, 1 => $_);
# print STDERR "DEBUG: add line: @l\n";
}
}else{
# print STDERR "DEBUG: add line: @l\n";
$iter = $store->append();
$store->set($iter, 0 => $words->{$f}, 1 => $parsed->{$f});
}
}
}
return($list);
}
1;
__END__
=head1 NAME
GUI::X509_infobox - show X.509 certificates and requests in a Gtk2::VBox
=head1 SYNOPSIS
use X509_infobox;
$infobox=X509_infobox->new();
$infobox->update($parent,$parsed,$mode,$title);
$infobox->update($parent,$parsed,$mode);
$infobox->hide();
=head1 DESCRIPTION
This displays the information of an X.509v3 certificate or
certification request (CSR) inside a given Gtk2::VBox.
Creation of an X509_infobox is done by calling B<new()>,
no arguments are required.
The infobox is shown when inserted into an already
existing Gtk2::VBox using the method B<update()>. Arguments
to update are:
=over 1
=item $parent:
the existing Gtk2::VBox inside which the info will be
displayed.
=item $parsed:
a structure returned by OpenSSL::parsecert() or OpenSSL::parsecrl()
containing the required information.
=item $mode:
what type of information is to be displayed. Valid modes
are 'req' (certification request), 'cert' (certificate), 'key' or 'cacert'
(same as certificate but without displaying the validity information
of the cert because this cannot be decided on from the view of the
actual CA).
=item $title:
if specified, a surrounding frame with the given title
is drawn.
=back
An existing infobox is destroyed by calling B<hide()>.
=cut

393
lib/HELPERS.pm Normal file
View File

@@ -0,0 +1,393 @@
# Copyright (c) Olaf Gellert <og@pre-secure.de> and
# Stephan Martin <sm@sm-zone.net>
#
# $Id: HELPERS.pm,v 1.6 2006/06/28 21:50:41 sm Exp $
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
use strict;
package HELPERS;
use POSIX;
my $version = "0.1";
my $true = 1;
my $false = undef;
#
# generate filename from Subject-DN
#
sub gen_name {
my $opts = shift;
my $name = '';
foreach (qw(CN EMAIL OU O L ST C)) {
if((not defined($opts->{$_})) || ($opts->{$_} eq '')) {
$opts->{$_} = ".";
}
if($opts->{$_} ne '.' && not ref($opts->{$_})) {
$name .= $opts->{$_};
} elsif (ref($opts->{$_})) {
if(defined($opts->{$_}->[0])) {
$name .= $opts->{$_}->[0];
} else {
$name .= " ";
}
} else {
$name .= " ";
}
$name .= ":" if($_ ne 'C');
}
return($name);
}
#
# generate temporary filename
#
sub mktmp {
my $base = shift;
my @rand = ();
my $ret = '';
do {
for(my $i = 0; $i < 8; $i++) {
push(@rand, int(rand 26)+65);
}
my $end = pack("C8", @rand);
$ret = $base.$end;
} while (-e $ret);
return($ret);
}
#
# finished...
#
sub exit_clean {
my ($ret) = @_;
$ret = 0 unless(defined $ret);
# hack to avoid busy cursor
my $rootwin = Gtk2::Gdk->get_default_root_window();
my $cursor = Gtk2::Gdk::Cursor->new('left-ptr');
$rootwin->set_cursor($cursor);
Gtk2->main_quit();
exit($ret);
}
#
# split Subject DN and return hash
#
sub parse_dn {
my $dn = shift;
my (@dn, $k, $v, $tmp);
$tmp = {};
$dn =~ s/,/\//g;
@dn = split(/\//, $dn);
foreach(@dn) {
s/^\s+//;
s/\s+$//;
($k, $v) = split(/=/);
next if(not defined($k));
if($k =~ /ou/i) {
$tmp->{'OU'} or $tmp->{'OU'} = [];
push(@{$tmp->{'OU'}}, $v);
} else {
if($k =~ /emailaddress/i) {
$tmp->{'EMAIL'} = $v;
} else {
$tmp->{uc($k)} = $v;
}
}
}
return($tmp);
}
#
# parse (requested) X509 extensions and return hash
#
sub parse_extensions {
my ($lines, $mode) = @_;
my ($sep, $i, $k, $v, $tmp);
$sep = $mode eq "req"?"Requested extensions:":"X509v3 extensions:";
$tmp = {};
# skip everything before the extensions
for($i = 0; defined($lines->[$i]) && $lines->[$i] !~ /^[\s\t]*$sep$/i; $i++) {
return(undef) if not defined($lines->[$i]);
}
$i++;
while($i < @{$lines}) {
if(($lines->[$i] =~ /^[\s\t]*[^:]+:\s*$/) ||
($lines->[$i] =~ /^[\s\t]*[^:]+:\s+.+$/)) {
if($lines->[$i] =~ /^[\s\t]*Signature Algorithm/i) {
$i++;
next;
}
$k = $lines->[$i];
$k =~ s/[\s\t:]*$//g;
$k =~ s/^[\s\t]*//g;
$tmp->{$k} = [];
$i++;
while(($lines->[$i] !~ /^[\s\t].+:\s*$/) &&
($lines->[$i] !~ /^[\s\t]*[^:]+:\s+.+$/) &&
($lines->[$i] !~ /^[\s\t]*Signature Algorithm/i) &&
($i < @{$lines})) {
$v = $lines->[$i];
$v =~ s/^[\s]+//g;
$v =~ s/[\s]+$//g;
$i++;
next if $v =~ /^$/;
next if $v =~ /Signature Algorithm:/;
my @vs = split(/,/, $v);
foreach(@vs) {
$_ =~ s/^\s//;
$_ =~ s/\s$//;
push(@{$tmp->{$k}}, $_);
}
}
} else {
$i++;
}
}
return($tmp);
}
#
# get last used export directory
#
sub get_export_dir {
my $main = shift;
open(EXPIN, "<$main->{'cadir'}/.exportdir") || return(undef);
my $dir = <EXPIN>;
chomp($dir);
return($dir);
}
#
# write last used export directory
#
sub write_export_dir {
my ($main, $dir) = @_;
$dir =~ s:/[^/]+$::;
open(EXPOUT, ">$main->{'cadir'}/.exportdir") || do {
my $t = sprintf(_("Can't write exportdir: %s, %s"),
"$main->{'cadir'}/.exportdir", $!);
GUI::HELPERS::print_warning($t);
return;
};
print EXPOUT "$dir\n";
close(EXPOUT);
return($dir);
}
#
# generate contents for subjectAltName
#
sub gen_subjectaltname_contents($@)
{
my $type = shift || '';
my @input = map { split/,\s*|\s+/, $_ } @_; # split on ',' and ' '
my %output = (); # uniq on the fly
if ($type) { # type given => use that one for all
foreach my $elem (@input) {
$output{$type.$elem} = 1;
}
}
else { # no type => use heuristigcs to guess type per element
foreach my $elem (@input) {
if ($elem =~ s/^(ip:|dns:)(.*)/$2/i) {
$type = uc($1);
} elsif ($elem =~ s/^(email:)(.*)/$2/i) {
$type = lc($1);
} else {
if ($elem =~ /^\d+\.\d+\.\d+\.\d+$/) { # it's an IP address
$type = 'IP:';
}
elsif ($elem =~ /^.+\@.+\.\w+$/) { # it's a mail address
$type = 'email:';
}
else {
$type = 'DNS:' # otherwise it's a DNS name
}
}
$output{$type.$elem} = 1;
}
}
return(wantarray ? keys(%output) : join(', ', keys(%output)));
}
sub enc_base64 {
my $data = shift;
my $ret = MIME::Base64::encode($data, '');
$ret =~ tr/\/+/-_/;
return $ret;
}
sub dec_base64 {
my $data = shift;
$data =~ tr/-_/\/+/;
return MIME::Base64::decode($data);
}
1
__END__
=head1 NAME
HELPERS - helper functions for TinyCA, doing small jobs not related to the GUI
=head1 SYNOPSIS
use HELPERS;
$name = HELPERS::gen_name($opts);
$tmpnam = HELPERS::mktmp($base);
$dnhash = HELPERS::parse_dn($dnstring);
$exthash = HELPERS::parse_extensions($mode, $lines);
$subjaltname = HELPERS::gen_subjectaltname_contents($type, @list);
exit_clean($retcode);
=head1 DESCRIPTION
HELPERS.pm is just a library, containing some useful functions used by other
TinyCA modules.
=head1 FUNCTIONS
=head2 HELPERS::gen_name($opts)
=over 1
returns a string with the TinyCA filename for a certificate, request or key.
The filename is generated from the following parts of the Subject DN from the
related request or certificate if present:
CN EMAIL OU O L ST C
These parts need to be elements in the given options hash.
=back
=head2 HELPERS::mktmp($base)
=over 1
returns a string, containing a uniqe filename starting with $base, which is
not existing yet.
$base needs to be an absolute path to allow HELPERS::mktmp() reliable check
that the filename is really uniqe.
=back
=head2 HELPERS::parse_dn($dnstring)
=over 1
returns the reference to a hash containing all elements of the Subject DN,
given in $dnstring.
The element OU is included as an array refernce in the hash, with an array
containing all values of OU.
=back
=head2 HELPERS::parse_extensions($mode, $lines)
=over 1
returns the reference to a hash containing all X509 extensions of the given
request or certificate.
The request or certificate is given in textform as an array reference
with the array containing one line per element.
$mode contains one of the strings "req" or "cert" depending on the type of the
data.
=back
=head2 HELPERS::exit_clean($retcode)
=over 1
does nothing yet, than closing the Gtk application returning the exitcode
given in $retcode.
=back
=head2 $main->HELPERS::get_export_dir()
=over 1
Get last used export directory.
=back
=head2 $main->HELPERS::write_export-dir($dir)
=over 1
Store last used export directory
=back
=head2 HELPERS::gen_subjectaltname_contents($type, @list)
=over 1
Generate a string suitable for the use as subjhectAltname contets for OpenSSL.
If $Type is not empty create the contents of that type only,
otherwise use either the type prefix of the list elements or
the following heuristics to find the type for the appropriate elements:
If the element looks like an IP address in dotted quad notation set
then treat it as one.
If the element contains a '@' followed by a '.' and a sequence of letters
then treat the element as an email address.
In all other cases treat it as a DNS name.
=back
=cut

494
lib/KEY.pm Normal file
View File

@@ -0,0 +1,494 @@
# Copyright (c) Stephan Martin <sm@sm-zone.net>
#
# $Id: KEY.pm,v 1.8 2006/06/28 21:50:41 sm Exp $
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
use strict;
package KEY;
use POSIX;
sub new {
my $self = {};
my $that = shift;
my $class = ref($that) || $that;
bless($self, $class);
}
#
# get name of keyfile to delete
#
sub get_del_key {
my ($self, $main) = @_;
my($keyname, $key, $keyfile, $row, $ind, $ca, $type);
$ca = $main->{'keybrowser'}->selection_caname();
$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_del_confirm($keyfile, 'key');
return;
}
#
# now really delete the key
#
sub del_key {
my ($self, $main, $file) = @_;
unlink($file);
my $cadir = $main->{'keybrowser'}->selection_cadir();
$main->{'keybrowser'}->update($cadir."/keys",
$cadir."/crl/crl.pem",
$cadir."/index.txt",
0);
return;
}
#
# read keys in directory into list
#
sub read_keylist {
my ($self, $main) = @_;
my ($f, $modt, $tmp, $ca, $keydir, $keylist);
$ca = $main->{'CA'}->{'actca'};
$keydir = $main->{'cadir'}."/keys";
$keylist = [];
$modt = (stat($keydir))[9];
if(defined($self->{'lastread'}) &&
$self->{'lastread'} >= $modt) {
return(0);
}
opendir(DIR, $keydir) || do {
GUI::HELPERS::print_warning(_("Can't open key directory"));
return(0);
};
while($f = readdir(DIR)) {
next if $f =~ /^\./;
$f =~ s/\.pem//;
$tmp = HELPERS::dec_base64($f);
next if not defined($tmp);
next if $tmp eq "";
$tmp = _check_key($main, $keydir."/".$f.".pem", $tmp);
push(@{$keylist}, $tmp);
}
@{$keylist} = sort(@{$keylist});
closedir(DIR);
$self->{'keylist'} = $keylist;
$self->{'lastread'} = time();
return(1); # got new list
}
#
# get the information to export the key
#
sub get_export_key {
my ($self, $main, $opts, $box) = @_;
$box->destroy() if(defined($box));
my($ca, $ind, $row, $t, $out, $cn, $email, $ret, $ext, $cadir);
if(not defined($opts)) {
$cn = $main->{'keybrowser'}->selection_cn();
if(not defined $cn) {
GUI::HELPERS::print_info(_("Please select a Key first"));
return;
}
$ca = $main->{'keybrowser'}->selection_caname();
$cadir = $main->{'keybrowser'}->selection_cadir();
$email = $main->{'keybrowser'}->selection_email();
$opts->{'type'} = $main->{'keybrowser'}->selection_type();
$opts->{'key'} = $main->{'keybrowser'}->selection_dn();
$opts->{'keyname'} = HELPERS::enc_base64($opts->{'key'});
$opts->{'keyfile'} = $cadir."/keys/".$opts->{'keyname'}.".pem";
$opts->{'certfile'} = $cadir."/certs/".$opts->{'keyname'}.".pem";
# set some defaults
$opts->{'nopass'} = 0;
$opts->{'include'} = 0;
$opts->{'format'} = 'PEM';
$opts->{'friendlyname'} = '';
if((defined($email)) && $email ne '' && $email ne ' ') {
$opts->{'outfile'} = "$main->{'exportdir'}/$email-key.pem";
}elsif((defined($cn)) && $cn ne '' && $cn ne ' ') {
$opts->{'outfile'} = "$main->{'exportdir'}/$cn-key.pem";
}else{
$opts->{'outfile'} = "$main->{'exportdir'}/key.pem";
}
$main->show_export_dialog($opts, 'key');
return;
}
if((not defined($opts->{'outfile'})) || ($opts->{'outfile'} eq '')) {
$main->show_export_dialog($opts, 'key');
GUI::HELPERS::print_warning(_("Please give at least the output file"));
return;
}
if(($opts->{'nopass'} || $opts->{'format'} eq 'DER') &&
((not defined($opts->{'passwd'})) || ($opts->{'passwd'} eq ''))) {
$main->show_key_nopasswd_dialog($opts);
return;
}
if(($opts->{'format'} eq 'PEM') || ($opts->{'format'} eq 'DER')) {
unless(($opts->{'format'} eq 'PEM') && not $opts->{'nopass'}) {
($out, $ext) = $main->{'OpenSSL'}->convkey(
'type' => $opts->{'type'},
'inform' => 'PEM',
'outform' => $opts->{'format'},
'nopass' => $opts->{'nopass'},
'pass' => $opts->{'passwd'},
'keyfile' => $opts->{'keyfile'}
);
if(defined($out) && $out eq 1) {
$t = _("Wrong password given\nDecrypting of the Key failed\nExport is not possible");
GUI::HELPERS::print_warning($t, $ext);
return;
} elsif((not defined($out)) || (length($out) < 3)) {
GUI::HELPERS::print_warning(
_("Converting failed, Export not possible"), $ext);
return;
}
}
if(($opts->{'format'} eq 'PEM') && not $opts->{'nopass'}) {
open(IN, "<$opts->{'keyfile'}") || do {
$t = sprintf(_("Can't open Key file: %s: %s"),
$opts->{'keyfile'}, $!);
GUI::HELPERS::print_warning($t);
return;
};
$out .= $_ while(<IN>);
close(IN);
}
if($opts->{'include'}) {
open(IN, "<$opts->{'certfile'}") || do {
$t = sprintf(_("Can't open Certificate file: %s: %s"),
$opts->{'certfile'}, $!);
GUI::HELPERS::print_warning($t);
return;
};
$out .= "\n";
$out .= $_ while(<IN>);
close(IN);
}
open(OUT, ">$opts->{'outfile'}") || do {
$t = sprintf(_("Can't open output file: %s: %s"),
$opts->{'outfile'}, $!);
GUI::HELPERS::print_warning($t);
return;
};
print OUT $out;
close(OUT);
$main->{'exportdir'} = HELPERS::write_export_dir($main,
$opts->{'outfile'});
$t = sprintf(_("Key succesfully exported to %s"),
$opts->{'outfile'});
GUI::HELPERS::print_info($t);
return;
} elsif ($opts->{'format'} eq 'P12') {
$opts->{'certfile'} =
$main->{'cadir'}."/certs/".$opts->{'keyname'}.".pem";
$opts->{'cafile'} =
$main->{'cadir'}."/cacert.pem";
if (-f $main->{'cadir'}."/cachain.pem") {
$opts->{'cafile'} = $main->{'cadir'}."/cachain.pem";
}
if(not -s $opts->{'certfile'}) {
$t = _("Certificate is necessary for export as PKCS#12");
$t .= "\n";
$t .= _("Export is not possible!");
GUI::HELPERS::print_warning($t);
return;
}
if((not defined($opts->{'p12passwd'})) &&
(not $opts->{'nopass'})) {
$opts->{'includeca'} = 1;
$main->show_p12_export_dialog($opts, 'key');
return;
}
unlink($opts->{'outfile'});
($ret, $ext) = $main->{'OpenSSL'}->genp12(
type => $opts->{'type'},
certfile => $opts->{'certfile'},
keyfile => $opts->{'keyfile'},
cafile => $opts->{'cafile'},
outfile => $opts->{'outfile'},
passwd => $opts->{'passwd'},
p12passwd => $opts->{'p12passwd'},
includeca => $opts->{'includeca'},
nopass => $opts->{'nopass'},
friendly => $opts->{'friendlyname'}
);
if($ret eq 1) {
$t = "Wrong password given\nDecrypting Key failed\nGenerating PKCS#12 failed";
GUI::HELPERS::print_warning($t, $ext);
return;
} elsif($ret || (not -s $opts->{'outfile'})) {
$t = _("Generating PKCS#12 failed");
return;
}
$main->{'exportdir'} = HELPERS::write_export_dir($main,
$opts->{'outfile'});
$t = sprintf(_("Certificate and Key successfully exported to %s"),
$opts->{'outfile'});
GUI::HELPERS::print_info($t, $ext);
return;
} elsif (($opts->{'format'} eq "ZIP") || ($opts->{'format'} eq "TAR")) {
$opts->{'certfile'} =
$main->{'cadir'}."/certs/".$opts->{'keyname'}.".pem";
if(not -s $opts->{'certfile'}) {
$t = sprintf(
_("Certificate is necessary for export as %s file"),
$opts->{'format'});
$t .= "\n";
$t .= _("Export is not possible!");
GUI::HELPERS::print_warning($t);
return;
}
$opts->{'parsed'} =
$main->{'CERT'}->parse_cert($main, $opts->{'keyname'});
my $tmpcert = "$main->{'tmpdir'}/cert.pem";
my $tmpkey = "$main->{'tmpdir'}/key.pem";
my $tmpcacert = "$main->{'tmpdir'}/cacert.pem";
open(OUT, ">$tmpcert") || do {
GUI::HELPERS::print_warning(_("Can't create temporary file"));
return;
};
print OUT $opts->{'parsed'}->{'PEM'};
close OUT;
# store key in temporary location
{
open(IN, "<$opts->{'keyfile'}") || do {
GUI::HELPERS::print_warning(_("Can't read Key file"));
return;
};
my @key = <IN>;
close IN;
open(OUT, ">$tmpkey") || do {
GUI::HELPERS::print_warning(_("Can't create temporary file"));
return;
};
print OUT @key;
close OUT;
}
# store cacert in temporary location
{
$opts->{'cafile'} = $main->{'cadir'}."/cacert.pem";
open(IN, "<$opts->{'cafile'}") || do {
GUI::HELPERS::print_warning(_("Can't read CA certificate"));
return;
};
my @cacert = <IN>;
close IN;
open(OUT, ">$tmpcacert") || do {
GUI::HELPERS::print_warning(_("Can't create temporary file"));
return;
};
print OUT @cacert;
close OUT;
}
unlink($opts->{'outfile'});
if($opts->{'format'} eq 'ZIP') {
system($main->{'init'}->{'zipbin'}, '-j', $opts->{'outfile'},
$tmpcacert, $tmpkey, $tmpcert);
my $ret = $? >> 8;
} elsif ($opts->{'format'} eq 'TAR') {
system($main->{'init'}->{'tarbin'}, 'cfv', $opts->{'outfile'},
$tmpcacert, $tmpkey, $tmpcert);
my $ret = $? >> 8;
}
if(not -s $opts->{'outfile'} || $ret) {
GUI::HELPERS::print_warning(
sprintf(_("Generating %s file failed"),
$opts->{'format'}));
} else {
$main->{'exportdir'} = HELPERS::write_export_dir($main,
$opts->{'outfile'});
$t = sprintf(
_("Certificate and Key successfully exported to %s"),
$opts->{'outfile'});
GUI::HELPERS::print_info($t);
}
unlink($tmpcacert);
unlink($tmpcert);
unlink($tmpkey);
return;
} else {
$t = sprintf(_("Invalid format for export requested: %s"),
$opts->{'format'});
GUI::HELPERS::print_warning($t);
return;
}
GUI::HELPERS::print_warning(_("Something Failed ??"));
return;
}
# check if its a dsa or rsa key
sub _check_key {
my ($main, $file, $name) = @_;
my ($t, $type);
open(KEY, "<$file") || do {
$t = sprintf(_("Can't open Key file: %s: %s"),
$file, $!);
GUI::HELPERS::print_warning($t);
return;
};
while(<KEY>) {
if(/RSA PRIVATE KEY/i) {
$type = "RSA";
last;
} elsif(/DSA PRIVATE KEY/i) {
$type = "DSA";
last;
} else {
$type = "UNKNOWN";
}
}
close(KEY);
if(defined($type) && $type ne "") {
$name .= "%".$type;
}
return($name);
}
sub key_change_passwd {
my ($self, $main, $file, $oldpass, $newpass) = @_;
my $opts = {};
my ($t, $ret, $ext);
my $inform = "DER";
my $outform = "PEM";
my($type);
# ckeck file format
open(KEY, "<$file") || do {
$t = sprintf(_("Can't open Key file:\n%s"),
$file);
GUI::HELPERS::print_warning($t);
return(1);
};
while(<KEY>) {
if(/BEGIN RSA PRIVATE KEY/) {
$inform = "PEM";
$type = "RSA";
last;
} elsif(/BEGIN RSA PRIVATE KEY/){
$inform = "PEM";
$type = "DSA";
last;
} else {
$type = "UNKNOWN";
}
}
GUI::HELPERS::set_cursor($main, 1);
($ret, $ext) = $main->{'OpenSSL'}->convkey(
'type' => $type,
'inform' => $inform,
'outform' => $outform,
'nopass' => 0,
'pass' => $newpass,
'oldpass' => $oldpass,
'keyfile' => $file
);
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");
}
GUI::HELPERS::print_warning(($t), $ext);
return($ret);
}
return($ret);
}
1

1079
lib/OpenSSL.pm Normal file

File diff suppressed because it is too large Load Diff

777
lib/REQ.pm Normal file
View File

@@ -0,0 +1,777 @@
# Copyright (c) Stephan Martin <sm@sm-zone.net>
#
# $Id: REQ.pm,v 1.7 2006/06/28 21:50:42 sm Exp $
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
use strict;
package REQ;
use POSIX;
sub new {
my $that = shift;
my $class = ref($that) || $that;
my $self = {};
$self->{'OpenSSL'} = shift;
bless($self, $class);
}
#
# check if all data for creating a new request is available
#
sub get_req_create {
my ($self, $main, $opts, $box) = @_;
$box->destroy() if(defined($box));
my ($name, $action, $parsed, $reqfile, $keyfile, $ca, $t);
$ca = $main->{'CA'}->{'actca'};
if(!(defined($opts)) || !(ref($opts))) {
if(defined($opts) && $opts eq "signserver") {
$opts = {};
$opts->{'sign'} = 1;
$opts->{'type'} = "server";
} elsif(defined($opts) && $opts eq "signclient") {
$opts = {};
$opts->{'sign'} = 1;
$opts->{'type'} = "client";
} elsif (defined($opts)) {
$t = sprintf(_("Strange value for 'opts': %s"), $opts);
GUI::HELPERS::print_error($t);
}
$opts->{'bits'} = 4096;
$opts->{'digest'} = 'sha1';
$opts->{'algo'} = 'rsa';
if(defined($opts) && $opts eq "sign") {
$opts->{'sign'} = 1;
}
$parsed = $main->{'CERT'}->parse_cert($main, 'CA');
defined($parsed) ||
GUI::HELPERS::print_error(_("Can't read CA certificate"));
# set defaults
if(defined $parsed->{'C'}) {
$opts->{'C'} = $parsed->{'C'};
}
if(defined $parsed->{'ST'}) {
$opts->{'ST'} = $parsed->{'ST'};
}
if(defined $parsed->{'L'}) {
$opts->{'L'} = $parsed->{'L'};
}
if(defined $parsed->{'O'}) {
$opts->{'O'} = $parsed->{'O'};
}
my $cc = 0;
foreach my $ou (@{$parsed->{'OU'}}) {
$opts->{'OU'}->[$cc++] = $ou;
}
$main->show_req_dialog($opts);
return;
}
if((not defined($opts->{'CN'})) ||
($opts->{'CN'} eq "") ||
(not defined($opts->{'passwd'})) ||
($opts->{'passwd'} eq "")) {
$main->show_req_dialog($opts);
GUI::HELPERS::print_warning(
_("Please specify at least Common Name ")
._("and Password"));
return;
}
if((not defined($opts->{'passwd2'})) ||
$opts->{'passwd'} ne $opts->{'passwd2'}) {
$main->show_req_dialog($opts);
GUI::HELPERS::print_warning(_("Passwords don't match"));
return;
}
$opts->{'C'} = uc($opts->{'C'});
if((defined $opts->{'C'}) &&
($opts->{'C'} ne "") &&
(length($opts->{'C'}) != 2)) {
$main->show_req_dialog($opts);
GUI::HELPERS::print_warning(
_("Country must be exact 2 letter code"));
return;
}
$name = HELPERS::gen_name($opts);
$opts->{'reqname'} = HELPERS::enc_base64($name);
$reqfile = $main->{'CA'}->{$ca}->{'dir'}."/req/".$opts->{'reqname'}.".pem";
$keyfile = $main->{'CA'}->{$ca}->{'dir'}."/keys/".$opts->{'reqname'}.".pem";
if(-s $reqfile || -s $keyfile) {
$main->show_req_overwrite_warning($opts);
return;
}
$self->create_req($main, $opts);
return;
}
#
# create new request and key
#
sub create_req {
my ($self, $main, $opts) = @_;
my($reqfile, $keyfile, $ca, $ret, $ext, $cadir);
GUI::HELPERS::set_cursor($main, 1);
$ca = $main->{'CA'}->{'actca'};
$cadir = $main->{'CA'}->{$ca}->{'dir'};
$reqfile = $cadir."/req/".$opts->{'reqname'}.".pem";
$keyfile = $cadir."/keys/".$opts->{'reqname'}.".pem";
($ret, $ext) = $self->{'OpenSSL'}->newkey(
'algo' => $opts->{'algo'},
'bits' => $opts->{'bits'},
'outfile' => $keyfile,
'pass' => $opts->{'passwd'}
);
if (not -s $keyfile || $ret) {
unlink($keyfile);
GUI::HELPERS::set_cursor($main, 0);
GUI::HELPERS::print_warning(_("Generating key failed"), $ext);
return;
}
my @dn = ( $opts->{'C'}, $opts->{'ST'}, $opts->{'L'}, $opts->{'O'} );
if(ref($opts->{'OU'})) {
foreach my $ou (@{$opts->{'OU'}}) {
push(@dn,$ou);
}
} else {
push(@dn, $opts->{'OU'});
}
@dn = (@dn, $opts->{'CN'}, $opts->{'EMAIL'}, '', '');
($ret, $ext) = $self->{'OpenSSL'}->newreq(
'config' => $main->{'CA'}->{$ca}->{'cnf'},
'outfile' => $reqfile,
'keyfile' => $keyfile,
'digest' => $opts->{'digest'},
'pass' => $opts->{'passwd'},
'dn' => \@dn,
);
if (not -s $reqfile || $ret) {
unlink($keyfile);
unlink($reqfile);
GUI::HELPERS::set_cursor($main, 0);
GUI::HELPERS::print_warning(_("Generating Request failed"), $ext);
return;
}
my $parsed = $self->parse_req($main, $opts->{'reqname'}, 1);
$main->{'reqbrowser'}->update($cadir."/req",
$cadir."/crl/crl.pem",
$cadir."/index.txt",
0);
$main->{'keybrowser'}->update($cadir."/keys",
$cadir."/crl/crl.pem",
$cadir."/index.txt",
0);
GUI::HELPERS::set_cursor($main, 0);
if($opts->{'sign'}) {
$opts->{'reqfile'} = $reqfile;
$opts->{'passwd'} = undef; # to sign request, ca-password is needed
$self->get_sign_req($main, $opts);
}
return;
}
#
# get name of requestfile to delete
#
sub get_del_req {
my ($self, $main) = @_;
my($reqname, $req, $reqfile, $row, $ind, $ca, $cadir);
$ca = $main->{'reqbrowser'}->selection_caname();
$cadir = $main->{'reqbrowser'}->selection_cadir();
if(not(defined($reqfile))) {
$req = $main->{'reqbrowser'}->selection_dn();
if(not defined($req)) {
GUI::HELPERS::print_info(_("Please select a Request first"));
return;
}
$reqname = HELPERS::enc_base64($req);
$reqfile = $cadir."/req/".$reqname.".pem";
}
if(not -s $reqfile) {
GUI::HELPERS::print_warning(_("Request file not found"));
return;
}
$main->show_del_confirm($reqfile, 'req');
return;
}
#
# now really delete the requestfile
#
sub del_req {
my ($self, $main, $file) = @_;
my ($ca, $cadir);
GUI::HELPERS::set_cursor($main, 1);
unlink($file);
$ca = $main->{'reqbrowser'}->selection_caname();
$cadir = $main->{'reqbrowser'}->selection_cadir();
$main->{'reqbrowser'}->update($cadir."/req",
$cadir."/crl/crl.pem",
$cadir."/index.txt",
0);
GUI::HELPERS::set_cursor($main, 0);
return;
}
sub read_reqlist {
my ($self, $reqdir, $crlfile, $indexfile, $force, $main) = @_;
my ($f, $modt, $d, $reqlist, $c, $p, $t);
GUI::HELPERS::set_cursor($main, 1);
$reqlist = [];
$modt = (stat($reqdir))[9];
if(defined($self->{'lastread'}) &&
$self->{'lastread'} >= $modt) {
GUI::HELPERS::set_cursor($main, 0);
return(0);
}
opendir(DIR, $reqdir) || do {
GUI::HELPERS::set_cursor($main, 0);
GUI::HELPERS::print_warning(_("Can't open Request directory"));
return(0);
};
while($f = readdir(DIR)) {
next if $f =~ /^\./;
$c++;
}
rewinddir(DIR);
$main->{'barbox'}->pack_start($main->{'progress'}, 0, 0, 0);
$main->{'progress'}->show();
while($f = readdir(DIR)) {
next if $f =~ /^\./;
$f =~ s/\.pem//;
$d = HELPERS::dec_base64($f);
next if not defined($d);
next if $d eq "";
push(@{$reqlist}, $d);
if(defined($main)) {
$t = sprintf(_(" Read Request: %s"), $d);
GUI::HELPERS::set_status($main, $t);
$p += 100/$c;
if($p/100 <= 1) {
$main->{'progress'}->set_fraction($p/100);
while(Gtk2->events_pending) {
Gtk2->main_iteration;
}
}
select(undef, undef, undef, 0.025);
}
}
@{$reqlist} = sort(@{$reqlist});
closedir(DIR);
delete($self->{'reqlist'});
$self->{'reqlist'} = $reqlist;
$self->{'lastread'} = time();
if(defined($main)) {
$main->{'progress'}->set_fraction(0);
$main->{'barbox'}->remove($main->{'progress'});
GUI::HELPERS::set_cursor($main, 0);
}
return(1); # got new list
}
#
# get name of request to sign
#
sub get_sign_req {
my ($self, $main, $opts, $box) = @_;
my($time, $parsed, $ca, $cadir, $ext, $ret);
$box->destroy() if(defined($box));
$time = time();
$ca = $main->{'reqbrowser'}->selection_caname();
$cadir = $main->{'reqbrowser'}->selection_cadir();
if(not(defined($opts->{'reqfile'}))) {
$opts->{'req'} = $main->{'reqbrowser'}->selection_dn();
if(not defined($opts->{'req'})) {
GUI::HELPERS::print_info(_("Please select a Request first"));
return;
}
$opts->{'reqname'} = HELPERS::enc_base64($opts->{'req'});
$opts->{'reqfile'} = $cadir."/req/".$opts->{'reqname'}.".pem";
}
if(not -s $opts->{'reqfile'}) {
GUI::HELPERS::print_warning(_("Request file not found"));
return;
}
if((-s $cadir."/certs/".$opts->{'reqname'}.".pem") &&
(!(defined($opts->{'overwrite'})) || ($opts->{'overwrite'} ne 'true'))) {
$main->show_cert_overwrite_confirm($opts);
return;
}
$parsed = $main->{'CERT'}->parse_cert($main, 'CA');
defined($parsed) ||
GUI::HELPERS::print_error(_("Can't read CA certificate"));
if(!defined($opts->{'passwd'})) {
$opts->{'days'} =
$main->{'TCONFIG'}->{$opts->{'type'}."_ca"}->{'default_days'};
if($opts->{'days'} > (($parsed->{'EXPDATE'}/86400) - ($time/86400))) {
$opts->{'days'} = int(($parsed->{'EXPDATE'}/86400) - ($time/86400));
}
$main->show_req_sign_dialog($opts);
return;
}
if((($time + ($opts->{'days'} * 86400)) > $parsed->{'EXPDATE'}) &&
(!(defined($opts->{'ignoredate'})) ||
$opts->{'ignoredate'} ne 'true')){
$main->show_req_date_warning($opts);
return;
}
# try to find message digest used for the request
$parsed = undef;
$parsed = $self->parse_req($main, $opts->{'reqname'}, 1);
defined($parsed) ||
GUI::HELPERS::print_error(_("Can't read Request file"));
if(defined($parsed->{'SIG_ALGORITHM'})) {
$opts->{'digest'} = $parsed->{'SIG_ALGORITHM'};
if($opts->{'digest'} =~ /^md2/) {
$opts->{'digest'} = "md2";
} elsif ($opts->{'digest'} =~ /^mdc2/) {
$opts->{'digest'} = "mdc2";
} elsif ($opts->{'digest'} =~ /^md4/) {
$opts->{'digest'} = "md4";
} elsif ($opts->{'digest'} =~ /^md5/) {
$opts->{'digest'} = "md5";
} elsif ($opts->{'digest'} =~ /^sha1/) {
$opts->{'digest'} = "sha1";
} elsif ($opts->{'digest'} =~ /^ripemd160/) {
$opts->{'digest'} = "ripemd160";
} else {
}
} else {
$opts->{'digest'} = 0;
}
($ret, $ext) = $self->sign_req($main, $opts);
return($ret, $ext);
}
#
# now really sign the request
#
sub sign_req {
my ($self, $main, $opts) = @_;
my($serial, $certout, $certfile, $certfile2, $ca, $cadir, $ret, $t, $ext);
GUI::HELPERS::set_cursor($main, 1);
$ca = $main->{'reqbrowser'}->selection_caname();
$cadir = $main->{'reqbrowser'}->selection_cadir();
$serial = $cadir."/serial";
open(IN, "<$serial") || do {
GUI::HELPERS::set_cursor($main, 0);
GUI::HELPERS::print_warning(_("Can't read serial"));
return;
};
$serial = <IN>;
chomp($serial);
close IN;
if(not defined($opts->{'nsSslServerName'})) {
$opts->{'nsSslServerName'} = 'none';
}
if(not defined($opts->{'nsRevocationUrl'})) {
$opts->{'nsRevocationUrl'} = 'none';
}
if(not defined($opts->{'nsRenewalUrl'})) {
$opts->{'nsRenewalUrl'} = 'none';
}
if(not defined($opts->{'subjectAltName'})) {
$opts->{'subjectAltName'} = 'none';
$opts->{'subjectAltNameType'} = 'none';
} else {
$opts->{'subjectAltNameType'} =
$main->{TCONFIG}->{$opts->{'type'}.'_cert'}->{'subjectAltNameType'};
}
if(not defined($opts->{'extendedKeyUsage'})) {
$opts->{'extendedKeyUsage'} = 'none';
$opts->{'extendedKeyUsageType'} = 'none';
} else {
$opts->{'extendedKeyUsageType'} =
$main->{TCONFIG}->{$opts->{'type'}.'_cert'}->{'extendedKeyUsageType'};
}
if(defined($opts->{'mode'}) && $opts->{'mode'} eq "sub") {
($ret, $ext) = $self->{'OpenSSL'}->signreq(
'mode' => $opts->{'mode'},
'config' => $main->{'CA'}->{$ca}->{'cnf'},
'reqfile' => $opts->{'reqfile'},
'keyfile' => $opts->{'keyfile'},
'cacertfile' => $opts->{'cacertfile'},
'outdir' => $opts->{'outdir'},
'days' => $opts->{'days'},
'parentpw' => $opts->{'parentpw'},
'caname' => "ca_ca",
'revocationurl' => $opts->{'nsRevocationUrl'},
'renewalurl' => $opts->{'nsRenewalUrl'},
'subjaltname' => $opts->{'subjectAltName'},
'subjaltnametype' => $opts->{'subjectAltNameType'},
'extendedkeyusage' => $opts->{'extendedKeyUsage'},
'extendedkeyusagetype' => $opts->{'extendedKeyUsageType'},
'noemaildn' => $opts->{'noemaildn'},
'digest' => $opts->{'digest'}
);
} else {
($ret, $ext) = $self->{'OpenSSL'}->signreq(
'config' => $main->{'CA'}->{$ca}->{'cnf'},
'reqfile' => $opts->{'reqfile'},
'days' => $opts->{'days'},
'pass' => $opts->{'passwd'},
'caname' => $opts->{'type'}."_ca",
'sslservername' => $opts->{'nsSslServerName'},
'revocationurl' => $opts->{'nsRevocationUrl'},
'renewalurl' => $opts->{'nsRenewalUrl'},
'subjaltname' => $opts->{'subjectAltName'},
'subjaltnametype' => $opts->{'subjectAltNameType'},
'extendedkeyusage' => $opts->{'extendedKeyUsage'},
'extendedkeyusagetype' => $opts->{'extendedKeyUsageType'},
'noemaildn' => $opts->{'noemaildn'},
'digest' => $opts->{'digest'}
);
}
GUI::HELPERS::set_cursor($main, 0);
if($ret eq 1) {
$t = _("Wrong CA password given\nSigning of the Request failed");
GUI::HELPERS::print_warning($t, $ext);
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
return;
} elsif($ret eq 2) {
$t = _("CA Key not found\nSigning of the Request failed");
GUI::HELPERS::print_warning($t, $ext);
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
return;
} elsif($ret eq 3) {
$t = _("Certificate already existing\nSigning of the Request failed");
GUI::HELPERS::print_warning($t, $ext);
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
return;
} elsif($ret eq 4) {
$t = _("Invalid IP Address given\nSigning of the Request failed");
GUI::HELPERS::print_warning($t, $ext);
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
return;
} elsif($ret) {
GUI::HELPERS::print_warning(
_("Signing of the Request failed"), $ext);
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
return($ret, $ext);
}
if(defined($opts->{'mode'}) && $opts->{'mode'} eq "sub") {
$certout = $cadir."/newcerts/".$serial.".pem";
$certfile = $opts->{'outfile'};
$certfile2 = $cadir."/certs/".$opts->{'reqname'}.".pem";
} else {
$certout = $cadir."/newcerts/".$serial.".pem";
$certfile = $cadir."/certs/".$opts->{'reqname'}.".pem";
#print STDERR "DEBUG: write certificate to: ".$cadir."/certs/".$opts->{'reqname'}.".pem";
}
if (not -s $certout) {
GUI::HELPERS::print_warning(
_("Signing of the Request failed"), $ext);
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
return;
}
open(IN, "<$certout") || do {
GUI::HELPERS::print_warning(_("Can't read Certificate file"));
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
return;
};
open(OUT, ">$certfile") || do {
GUI::HELPERS::print_warning(_("Can't write Certificate file"));
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
return;
};
print OUT while(<IN>);
if(defined($opts->{'mode'}) && $opts->{'mode'} eq "sub") {
close OUT;
open(OUT, ">$certfile2") || do {
GUI::HELPERS::print_warning(_("Can't write Certificate file"));
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
return;
};
seek(IN, 0, 0);
print OUT while(<IN>);
}
close IN; close OUT;
GUI::HELPERS::print_info(
_("Request signed succesfully.\nCertificate created"), $ext);
GUI::HELPERS::set_cursor($main, 1);
$main->{'CERT'}->reread_cert($main,
HELPERS::dec_base64($opts->{'reqname'}));
$main->{'certbrowser'}->update($cadir."/certs",
$cadir."/crl/crl.pem",
$cadir."/index.txt",
0);
delete($opts->{$_}) foreach(keys(%$opts));
$opts = undef;
GUI::HELPERS::set_cursor($main, 0);
return($ret, $ext);
}
#
# get informations/verifications to import request from file
#
sub get_import_req {
my ($self, $main, $opts, $box) = @_;
my ($ret, $ext, $der);
$box->destroy() if(defined($box));
my($ca, $parsed, $file, $format);
$ca = $main->{'CA'}->{'actca'};
if(not defined($opts)) {
$main->show_req_import_dialog();
return;
}
if(not defined($opts->{'infile'})) {
$main->show_req_import_dialog();
GUI::HELPERS::print_warning(_("Please select a Request file first"));
return;
}
if(not -s $opts->{'infile'}) {
$main->show_req_import_dialog();
GUI::HELPERS::print_warning(
_("Can't find Request file: ").$opts->{'infile'});
return;
}
open(IN, "<$opts->{'infile'}") || do {
GUI::HELPERS::print_warning(
_("Can't read Request file:").$opts->{'infile'});
return;
};
$opts->{'in'} .= $_ while(<IN>);
if($opts->{'in'} =~ /-BEGIN[\s\w]+CERTIFICATE REQUEST-/i) {
$format = "PEM";
$file = $opts->{'infile'};
} else {
$format = "DER";
}
if($format eq "DER") {
($ret, $der, $ext) = $opts->{'in'} = $self->{'OpenSSL'}->convdata(
'cmd' => 'req',
'data' => $opts->{'in'},
'inform' => 'DER',
'outform' => 'PEM'
);
if($ret) {
GUI::HELPERS::print_warning(
_("Error converting Request"), $ext);
return;
}
$opts->{'tmpfile'} =
HELPERS::mktmp($self->{'OpenSSL'}->{'tmp'}."/import");
open(TMP, ">$opts->{'tmpfile'}") || do {
GUI::HELPERS::print_warning( _("Can't create temporary file: %s: %s"),
$opts->{'tmpfile'}, $!);
return;
};
print TMP $opts->{'in'};
close(TMP);
$file = $opts->{'tmpfile'};
}
$parsed = $self->{'OpenSSL'}->parsereq(
$main->{'CA'}->{$ca}->{'cnf'},
$file);
if(not defined($parsed)) {
unlink($opts->{'tmpfile'});
GUI::HELPERS::print_warning(_("Parsing Request failed"));
return;
}
$main->show_import_verification("req", $opts, $parsed);
return;
}
#
# import request
#
sub import_req {
my ($self, $main, $opts, $parsed, $box) = @_;
my ($ca, $cadir);
$box->destroy() if(defined($box));
GUI::HELPERS::set_cursor($main, 1);
$ca = $main->{'reqbrowser'}->selection_caname();
$cadir = $main->{'reqbrowser'}->selection_cadir();
$opts->{'name'} = HELPERS::gen_name($parsed);
$opts->{'reqname'} = HELPERS::enc_base64($opts->{'name'});
$opts->{'reqfile'} = $cadir."/req/".$opts->{'reqname'}.".pem";
open(OUT, ">$opts->{'reqfile'}") || do {
unlink($opts->{'tmpfile'});
GUI::HELPERS::set_cursor($main, 0);
GUI::HELPERS::print_warning(_("Can't open output file: %s: %s"),
$opts->{'reqfile'}, $!);
return;
};
print OUT $opts->{'in'};
close OUT;
$main->{'reqbrowser'}->update($cadir."/req",
$cadir."/crl/crl.pem",
$cadir."/index.txt",
0);
GUI::HELPERS::set_cursor($main, 0);
return;
}
sub parse_req {
my ($self, $main, $name, $force) = @_;
my ($parsed, $ca, $reqfile, $req);
GUI::HELPERS::set_cursor($main, 1);
$ca = $main->{'CA'}->{'actca'};
$reqfile = $main->{'CA'}->{$ca}->{'dir'}."/req/".$name.".pem";
$parsed = $self->{'OpenSSL'}->parsereq($main->{'CA'}->{$ca}->{'cnf'},
$reqfile, $force);
GUI::HELPERS::set_cursor($main, 0);
return($parsed);
}
1

555
lib/TCONFIG.pm Normal file
View File

@@ -0,0 +1,555 @@
# Copyright (c) Stephan Martin <sm@sm-zone.net>
#
# $Id: TCONFIG.pm,v 1.2 2006/06/28 21:50:42 sm Exp $
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
use strict;
package TCONFIG;
use POSIX;
sub new {
my $self = {};
my $that = shift;
my $class = ref($that) || $that;
bless($self, $class);
}
sub init_config {
my ($self, $main, $ca) = @_;
my($file, @lines, $i, $section, $l, $k, $v);
if(not defined($ca)) {
$ca = $main->{'CA'}->{'actca'};
}
if(not defined($ca)) {
GUI::HELPERS::print_warning(_("Please select a CA first"));
return;
}
$file = $main->{'CA'}->{$ca}->{'cnf'};
open(IN, "<$file") || do {
GUI::HELPERS::print_warning(_("Can't open configuration"));
return;
};
@lines = <IN>;
close IN;
chomp(@lines);
# clean old configuration
foreach $k (keys(%$self)) {
delete($self->{$k});
}
foreach $l (@lines) {
next if $l =~ /^#/;
next if $l =~ /^$/;
next if $l =~ /^ *$/;
# find section
if($l =~ /\[\s*([^\s]+)\s*\]/) {
$section = $1;
} elsif ($l =~ /^([^\s\t]+)[\s\t]*=[\s\t]*([^\s\t]+.*)$/) {
if($section eq "ca" ||
$section eq "policy_client" ||
$section eq "policy_server" ||
$section eq "policy_ca" ||
$section eq "req" ||
$section eq "req_distinguished_name" ||
$section eq "v3_req" ||
$section eq "req_attributes") {
if(not defined($self->{$section})) {
$self->{$section} = [];
}
push(@{$self->{$section}}, $l);
} else {
$k = $1;
$v = $2;
# really ugly hack XXX
if($v =~ /ENV::(\w+)$/) {
$ENV{$1} = 'dummy';
}
if(not defined($self->{$section})) {
$self->{$section} = {};
}
$self->{$section}->{$k} = $v;
}
}
}
# store nsSslServerName information
if(defined($self->{'server_cert'}->{'nsSslServerName'})) {
if($self->{'server_cert'}->{'nsSslServerName'}
=~ /ENV:/) {
$self->{'server_cert'}->{'nsSslServerName'} = 'user';
}
}else {
$self->{'server_cert'}->{'nsSslServerName'} = 'none';
}
# store subjectAltName information
# ca
if(defined($self->{'v3_ca'}->{'subjectAltName'})) {
if($self->{'v3_ca'}->{'subjectAltName'} eq 'email:copy') {
$self->{'v3_ca'}->{'subjectAltName'} = 'emailcopy';
}
}else {
$self->{'v3_ca'}->{'subjectAltName'} = 'none';
}
# server
if(defined($self->{'server_cert'}->{'subjectAltName'})) {
if($self->{'server_cert'}->{'subjectAltName'}
=~ /ENV:.*IP/) {
$self->{'server_cert'}->{'subjectAltNameType'} = 'ip';
$self->{'server_cert'}->{'subjectAltName'} = 'user';
}elsif($self->{'server_cert'}->{'subjectAltName'}
=~ /ENV:.*DNS/) {
$self->{'server_cert'}->{'subjectAltNameType'} = 'dns';
$self->{'server_cert'}->{'subjectAltName'} = 'user';
}elsif($self->{'server_cert'}->{'subjectAltName'}
=~ /ENV:.*RAW/) {
$self->{'server_cert'}->{'subjectAltNameType'} = 'raw';
$self->{'server_cert'}->{'subjectAltName'} = 'user';
}elsif($self->{'server_cert'}->{'subjectAltName'}
eq 'email:copy') {
$self->{'server_cert'}->{'subjectAltName'} = 'emailcopy';
$self->{'server_cert'}->{'subjectAltNameType'} = 'ip';
}
}else {
$self->{'server_cert'}->{'subjectAltNameType'} = 'ip';
$self->{'server_cert'}->{'subjectAltName'} = 'none';
}
# client
if(defined($self->{'client_cert'}->{'subjectAltName'})) {
if($self->{'client_cert'}->{'subjectAltName'}
=~ /ENV:.*IP/) {
$self->{'client_cert'}->{'subjectAltNameType'} = 'ip';
$self->{'client_cert'}->{'subjectAltName'} = 'user';
}elsif($self->{'client_cert'}->{'subjectAltName'}
=~ /ENV:.*DNS/) {
$self->{'client_cert'}->{'subjectAltNameType'} = 'dns';
$self->{'client_cert'}->{'subjectAltName'} = 'user';
}elsif($self->{'client_cert'}->{'subjectAltName'}
=~ /ENV:.*EMAIL/) {
$self->{'client_cert'}->{'subjectAltNameType'} = 'mail';
$self->{'client_cert'}->{'subjectAltName'} = 'user';
}elsif($self->{'client_cert'}->{'subjectAltName'}
=~ /ENV:.*RAW/) {
$self->{'client_cert'}->{'subjectAltNameType'} = 'raw';
$self->{'client_cert'}->{'subjectAltName'} = 'user';
}elsif($self->{'client_cert'}->{'subjectAltName'}
eq 'email:copy') {
$self->{'client_cert'}->{'subjectAltName'} = 'emailcopy';
$self->{'client_cert'}->{'subjectAltNameType'} = 'ip';
}
}else {
$self->{'client_cert'}->{'subjectAltNameType'} = 'ip';
$self->{'client_cert'}->{'subjectAltName'} = 'none';
}
foreach my $sect ('server_cert', 'client_cert', 'v3_ca') {
# store nsRevocationUrl information
if(defined($self->{$sect}->{'nsRevocationUrl'})) {
if($self->{$sect}->{'nsRevocationUrl'}
=~ /ENV:/) {
$self->{$sect}->{'nsRevocationUrl'} = 'user';
}
}else {
$self->{$sect}->{'nsRevocationUrl'} = 'none';
}
# store nsRenewalUrl information
if(defined($self->{$sect}->{'nsRenewalUrl'})) {
if($self->{$sect}->{'nsRenewalUrl'}
=~ /ENV:/) {
$self->{$sect}->{'nsRenewalUrl'} = 'user';
}
}else {
$self->{$sect}->{'nsRenewalUrl'} = 'none';
}
# store extendedKeyUsage information
if(defined($self->{$sect}->{'extendedKeyUsage'})) {
if($self->{$sect}->{'extendedKeyUsage'} =~ /critical/) {
$self->{$sect}->{'extendedKeyUsageType'} = 'critical';
$self->{$sect}->{'extendedKeyUsage'} =~ s/critical\s*,\s*//;
}else {
$self->{$sect}->{'extendedKeyUsageType'} = 'noncritical';
}
if($self->{$sect}->{'extendedKeyUsage'}
=~ /ENV:/) {
$self->{$sect}->{'extendedKeyUsage'} = 'user';
}
}else {
$self->{$sect}->{'extendedKeyUsage'} = 'none';
$self->{$sect}->{'extendedKeyUsageType'} = 'noncritical';
}
# store keyUsage information
if(defined($self->{$sect}->{'keyUsage'})) {
if($self->{$sect}->{'keyUsage'} =~ /critical/) {
$self->{$sect}->{'keyUsageType'} = 'critical';
}else {
$self->{$sect}->{'keyUsageType'} = 'noncritical';
}
if($self->{$sect}->{'keyUsage'}
=~ /digitalSignature, keyEncipherment/) {
$self->{$sect}->{'keyUsage'} = 'keysig';
} elsif($self->{$sect}->{'keyUsage'}
=~ /digitalSignature/) {
$self->{$sect}->{'keyUsage'} = 'sig';
} elsif($self->{$sect}->{'keyUsage'}
=~ /keyEncipherment/) {
$self->{$sect}->{'keyUsage'} = 'key';
} elsif($self->{$sect}->{'keyUsage'}
=~ /keyCertSign, cRLSign/) {
$self->{$sect}->{'keyUsage'} = 'keyCertSign, cRLSign';
} elsif($self->{$sect}->{'keyUsage'}
=~ /keyCertSign/) {
$self->{$sect}->{'keyUsage'} = 'keyCertSign';
} elsif($self->{$sect}->{'keyUsage'}
=~ /cRLSign/) {
$self->{$sect}->{'keyUsage'} = 'cRLSign';
}else {
$self->{$sect}->{'keyUsage'} = 'none';
}
}else {
$self->{$sect}->{'keyUsage'} = 'none';
$self->{$sect}->{'keyUsageType'} = 'noncritical';
}
}
# hack to add new section to openssl.cnf, if old config
if(not defined($self->{'ca_ca'})) {
$self->{'ca_ca'} = $self->{'server_ca'};
$self->{'ca_ca'}->{'x509_extensions'} = "v3_ca";
$self->{'server_ca'}->{'x509_extensions'} = "server_cert";
$self->write_config($main, $ca);
}
if($self->{'server_ca'}->{'x509_extensions'} eq "v3_ca") {
$self->{'server_ca'}->{'x509_extensions'} = "server_cert";
$self->write_config($main, $ca);
}
# hack to add new option
if(not defined($self->{'ca_ca'}->{'unique_subject'})) {
$self->{'ca_ca'}->{'unique_subject'} = "yes";
$self->write_config($main, $ca);
}
if(not defined($self->{'server_ca'}->{'unique_subject'})) {
$self->{'server_ca'}->{'unique_subject'} = "yes";
$self->write_config($main, $ca);
}
if(not defined($self->{'client_ca'}->{'unique_subject'})) {
$self->{'client_ca'}->{'unique_subject'} = "yes";
$self->write_config($main, $ca);
}
return;
}
sub config_ca {
my ($self, $main, $ca) = @_;
my($action);
if(not defined($ca)) {
$ca = $main->{'CA'}->{'actca'};
}
if(not defined($ca)) {
GUI::HELPERS::print_warning(_("Can't get CA name"));
}
$action = GUI::TCONFIG::show_config_ca($main, $ca);
return;
}
sub config_openssl {
my ($self, $main, $ca) = @_;
if(not defined($ca)) {
$ca = $main->{'CA'}->{'actca'};
}
if(not defined($ca)) {
GUI::HELPERS::print_warning(_("Can't get CA name"));
}
GUI::TCONFIG::show_configbox($main, $ca);
return;
}
sub write_config {
my ($self, $main, $ca) = @_;
my($file, @sections, $line, $sect, $key, $val, @opts);
# these sections are not configurable
@sections = qw(
ca
policy_client
policy_server
policy_ca
req
req_distinguished_name
v3_req
req_attributes
);
$file = $main->{'CA'}->{$ca}->{'cnf'};
open(OUT, ">$file") || do {
GUI::HELPERS::print_warning(_("Can't open configfile"));
return;
};
foreach $sect (@sections) {
print OUT "[ $sect ]\n";
foreach $line (@{$self->{$sect}}) {
print OUT "$line\n";
}
print OUT "\n";
}
# these sections are configurable
@sections = qw(
v3_ca
crl_ext
server_ca
client_ca
ca_ca
client_cert
server_cert
);
foreach $sect (@sections) {
print OUT "[ $sect ]\n";
if($sect eq "v3_ca") {
@opts = qw(
subjectKeyIdentifier
authorityKeyIdentifier
basicConstraints
nsCertType
issuerAltName
nsComment
crlDistributionPoints
nsCaRevocationUrl
nsCaPolicyUrl
nsRevocationUrl
nsRenewalUrl
);
foreach $key (@opts) {
if(defined($self->{$sect}->{$key}) &&
$self->{$sect}->{$key} ne '' &&
$self->{$sect}->{$key} ne 'none') {
print OUT "$key = $self->{$sect}->{$key}\n";
}
}
if(defined($self->{$sect}->{'subjectAltName'})) {
if($self->{$sect}->{'subjectAltName'} eq 'emailcopy') {
print OUT "subjectAltName = email:copy\n";
} elsif($self->{$sect}->{'subjectAltName'} eq 'none') {
;# do nothing
}
}
if(defined($self->{$sect}->{'keyUsage'})) {
if($self->{$sect}->{'keyUsage'} eq 'keyCertSign') {
if($self->{$sect}->{'keyUsageType'} eq 'critical') {
print OUT "keyUsage = critical, keyCertSign\n";
} else {
print OUT "keyUsage = keyCertSign\n";
}
}elsif($self->{$sect}->{'keyUsage'} eq 'cRLSign') {
if($self->{$sect}->{'keyUsageType'} eq 'critical') {
print OUT "keyUsage = critical, cRLSign\n";
}else {
print OUT "keyUsage = cRLSign\n";
}
}elsif($self->{$sect}->{'keyUsage'} eq 'keyCertSign, cRLSign') {
if($self->{$sect}->{'keyUsageType'} eq 'critical') {
print OUT "keyUsage = critical, keyCertSign, cRLSign\n";
}else {
print OUT "keyUsage = keyCertSign, cRLSign\n";
}
}elsif($self->{$sect}->{'keyUsage'} eq 'none') {
;# do nothing
}
}
} elsif($sect eq "server_cert" ||
$sect eq "client_cert") {
@opts = qw(
basicConstraints
nsCertType
nsComment
subjectKeyIdentifier
authorityKeyIdentifier
issuerAltName
crlDistributionPoints
nsCaRevocationUrl
nsBaseUrl
nsCaPolicyUrl
);
foreach $key (@opts) {
if(defined($self->{$sect}->{$key}) &&
$self->{$sect}->{$key} ne '' &&
$self->{$sect}->{$key} ne 'none') {
print OUT "$key = $self->{$sect}->{$key}\n";
}
}
if(defined($self->{$sect}->{'nsSslServerName'})) {
if($self->{$sect}->{'nsSslServerName'} eq 'user') {
print OUT "nsSslServerName = \$ENV::NSSSLSERVERNAME\n";
} elsif($self->{$sect}->{'nsSslServerName'} eq 'none') {
;# do nothing
}
}
if(defined($self->{$sect}->{'nsRevocationUrl'})) {
if($self->{$sect}->{'nsRevocationUrl'} eq 'user') {
print OUT "nsRevocationUrl = \$ENV::NSREVOCATIONURL\n";
} elsif($self->{$sect}->{'nsRevocationUrl'} eq 'none') {
;# do nothing
}
}
if(defined($self->{$sect}->{'nsRenewalUrl'})) {
if($self->{$sect}->{'nsRenewalUrl'} eq 'user') {
print OUT "nsRenewalUrl = \$ENV::NSRENEWALURL\n";
} elsif($self->{$sect}->{'nsRenewalUrl'} eq 'none') {
;# do nothing
}
}
if(defined($self->{$sect}->{'subjectAltName'})) {
if($self->{$sect}->{'subjectAltName'} eq 'user') {
if($self->{$sect}->{'subjectAltNameType'} eq 'ip') {
print OUT "subjectAltName = \$ENV::SUBJECTALTNAMEIP\n";
} elsif($self->{$sect}->{'subjectAltNameType'} eq 'dns') {
print OUT "subjectAltName = \$ENV::SUBJECTALTNAMEDNS\n";
} elsif($self->{$sect}->{'subjectAltNameType'} eq 'mail') {
print OUT "subjectAltName = \$ENV::SUBJECTALTNAMEEMAIL\n";
} elsif($self->{$sect}->{'subjectAltNameType'} eq 'raw') {
print OUT "subjectAltName = \$ENV::SUBJECTALTNAMERAW\n";
}
} elsif($self->{$sect}->{'subjectAltName'} eq 'emailcopy') {
print OUT "subjectAltName = email:copy\n";
} elsif($self->{$sect}->{'subjectAltName'} eq 'none') {
;# do nothing
}
}
if(defined($self->{$sect}->{'keyUsage'})) {
if($self->{$sect}->{'keyUsage'} eq 'key') {
if($self->{$sect}->{'keyUsageType'} eq 'critical') {
print OUT "keyUsage = critical, keyEncipherment\n";
} else {
print OUT "keyUsage = keyEncipherment\n";
}
}elsif($self->{$sect}->{'keyUsage'} eq 'sig') {
if($self->{$sect}->{'keyUsageType'} eq 'critical') {
print OUT "keyUsage = critical, digitalSignature\n";
}else {
print OUT "keyUsage = digitalSignature\n";
}
}elsif($self->{$sect}->{'keyUsage'} eq 'keysig') {
if($self->{$sect}->{'keyUsageType'} eq 'critical') {
print OUT "keyUsage = critical, digitalSignature, keyEncipherment\n";
}else {
print OUT "keyUsage = digitalSignature, keyEncipherment\n";
}
}elsif($self->{$sect}->{'keyUsage'} eq 'none') {
;# do nothing
}
}
if(defined($self->{$sect}->{'extendedKeyUsage'})) {
if(($self->{$sect}->{'extendedKeyUsage'} ne 'none') &&
($self->{$sect}->{'extendedKeyUsage'} ne '')) {
if($self->{$sect}->{'extendedKeyUsage'} eq 'user') {
if($self->{$sect}->{'extendedKeyUsageType'} eq 'critical') {
print OUT "extendedKeyUsage = critical, \$ENV::EXTENDEDKEYUSAGE\n";
} else {
print OUT "extendedKeyUsage = \$ENV::EXTENDEDKEYUSAGE\n";
}
} else {
if($self->{$sect}->{'extendedKeyUsageType'} eq 'critical') {
print OUT "extendedKeyUsage = critical, $self->{$sect}->{'extendedKeyUsage'}\n";
} else {
print OUT "extendedKeyUsage = $self->{$sect}->{'extendedKeyUsage'}\n";
}
}
} elsif ($self->{$sect}->{'extendedKeyUsage'} eq 'none') {
;# do nothing
}
}
} elsif(($sect eq "server_ca") ||
($sect eq "client_ca") ||
($sect eq "ca_ca")) {
@opts = qw(
dir
certs
crl_dir
database
new_certs_dir
certificate
serial
crl
private_key
RANDFILE
x509_extensions
default_days
default_crl_days
default_md
preserve
policy
unique_subject
);
foreach $key (@opts) {
if(defined($self->{$sect}->{$key}) &&
$self->{$sect}->{$key} ne '' &&
$self->{$sect}->{$key} ne 'none') {
print OUT "$key = $self->{$sect}->{$key}\n";
}
}
} else {
while(($key, $val) = each(%{$self->{$sect}})) {
if(defined($val) && $val ne "") {
print OUT "$key = $val\n";
}
}
}
print OUT "\n";
}
close OUT;
# print STDERR "DEBUG: wrote config and reinit\n";
# $self->init_config($main, $ca);
return;
}
1