Blame SOURCES/genkey.pl

4418f4
#!%INSTDIR%/bin/perl
4418f4
#
4418f4
# This program is free software; you can redistribute it and/or
4418f4
# modify it under the terms of the GNU General Public License
4418f4
# as published by the Free Software Foundation; either version 2
4418f4
# of the License, or (at your option) any later version.
4418f4
# 
4418f4
# This program is distributed in the hope that it will be useful,
4418f4
# but WITHOUT ANY WARRANTY; without even the implied warranty of
4418f4
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4418f4
# GNU General Public License for more details.
4418f4
# 
4418f4
# You should have received a copy of the GNU General Public License
4418f4
# along with this program; if not, write to the Free Software
4418f4
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
4418f4
# 02110-1301, US
4418f4
#
4418f4
# Generate a keypair.  Get a keysize from the user, generate
4418f4
# some useful random data, generate a key, produce a CSR if
4418f4
# required and add a passphrase if required.
4418f4
#
4418f4
# genkey.pl -- based on genkey and genkey.aux from Stronghold
4418f4
#
4418f4
# Mark J Cox, mjc@redhat.com and Joe Orton, jorton@redhat.com
4418f4
#
4418f4
# 200103 Initial version
4418f4
# 200106 Converted to Newt
4418f4
# 200106 Added gencert/genreq functionality
4418f4
# 200106 Added some state
4418f4
# 200111 Added makeca functionality
4418f4
# 200305 Hide passwords entered for private key
4418f4
# 200308 Adapted for Taroon
4418f4
# 200308 Fix warnings in UTF-8 locale
4418f4
# 200409 Added --days support
4418f4
# 200804 Use NSS library for cryptography [Bug 346731]
4418f4
#
4418f4
#
4418f4
$bindir = "%INSTDIR%/bin";
4418f4
$ssltop = "%INSTDIR%/conf/ssl";
4418f4
$nssconf = "/etc/httpd/conf.d/nss.conf";
4418f4
$cadir = "$ssltop/CA";
4418f4
4418f4
use Crypt::Makerand;
4418f4
use Newt;
4418f4
use Getopt::Long;
4418f4
use File::Temp qw/ tempfile /;
4418f4
4418f4
sub InitRoot
4418f4
{
4418f4
    my $help = shift;
4418f4
4418f4
    Newt::Cls();
4418f4
    Newt::DrawRootText(0, 0, 
4418f4
		       "Red Hat Keypair Generation (c) 2008 Red Hat, Inc.");
4418f4
4418f4
    if ($help == 1) {
4418f4
	Newt::PushHelpLine("  <Tab>/<Alt-Tab> between elements  |" .
4418f4
			   "  <Space> selects  |" .
4418f4
			   "  <Escape> to quit");
4418f4
    }
4418f4
}
4418f4
4418f4
sub FinishRoot
4418f4
{
4418f4
    Newt::PopHelpLine();
4418f4
    Newt::Cls();
4418f4
}
4418f4
4418f4
sub usage 
4418f4
{
4418f4
    print STDERR <
4418f4
Usage: genkey [options] servername
4418f4
    --test   Test mode, faster seeding, overwrite existing key
4418f4
    --genreq Generate a Certificate Signing Request (CSR)
4418f4
    --makeca Generate a self-signed certificate for a CA
4418f4
    --days   Days until expiry of self-signed certificate (default 30)
4418f4
    --renew  CSR is for cert renewal, reusing existing key pair, openssl certs only
4418f4
    --cacert Renewal is for a CA certificate, needed for openssl certs only
4418f4
    --nss    Use the nss database for keys and certificates
4418f4
    --gdb    For package maintainers, to trace into the nss utilities
4418f4
EOH
4418f4
    exit 1;
4418f4
}
4418f4
4418f4
# Run a form with support for pressing escape and enter.
4418f4
sub RunForm
4418f4
{
4418f4
    my ($panel, $onenter, $onescape) = @_;
4418f4
    
4418f4
    # set defaults
4418f4
    $onenter = "Next" if (!defined($onenter));
4418f4
    $onescape = "Cancel" if (!defined($onescape));    
4418f4
4418f4
    $panel->AddHotKey(Newt::NEWT_KEY_ESCAPE());
4418f4
    $panel->AddHotKey(Newt::NEWT_KEY_ENTER()) unless $onenter eq "Ignore";
4418f4
4418f4
    ($reason, $data) = $panel->Run();
4418f4
4418f4
    if ($reason eq Newt::NEWT_EXIT_HOTKEY) {
4418f4
	if ($data == Newt::NEWT_KEY_ESCAPE()) {
4418f4
	    # They pressed ESCAPE; pretend they pressed "Cancel" or "No"
4418f4
	    return $onescape;
4418f4
	}
4418f4
	elsif ($data == Newt::NEWT_KEY_ENTER()) {
4418f4
	    my $current = $panel->GetCurrent();
4418f4
	    if ($panel->{refs}{$$current}->Tag()) {
4418f4
		# They pressed ENTER over a button; pretend they pressed it.
4418f4
		return $panel->{refs}{$$current}->Tag();
4418f4
	    }
4418f4
	    return $onenter;
4418f4
	}
4418f4
    }
4418f4
    elsif ($reason eq Newt::NEWT_EXIT_COMPONENT) {
4418f4
	return $data->Tag();
4418f4
    }
4418f4
    die "unhandled event ", $reason, " ", $data, "\n";
4418f4
}
4418f4
4418f4
#
4418f4
# main
4418f4
#
4418f4
4418f4
my $test_mode = '';
4418f4
my $genreq_mode = '';
4418f4
my $ca_mode = '';
4418f4
my $cert_days = 30;
4418f4
my $nss ='';
4418f4
my $renew = '';
4418f4
my $cacert = '';
4418f4
my $modNssDbDir = '';
4418f4
my $nssNickname = '';
4418f4
my $nssDBPrefix = '';
4418f4
my $gdb = '';
4418f4
GetOptions('test|t' => \$test_mode, 
4418f4
           'genreq' => \$genreq_mode,
4418f4
           'days=i' => \$cert_days,
4418f4
           'renew'  => \$renew,
4418f4
           'cacert' => \$cacert,
4418f4
           'nss|n'  => \$nss,
4418f4
           'gdb'    => \$gdb,
4418f4
           'makeca' => \$ca_mode) or usage();
4418f4
usage() unless @ARGV != 0;
4418f4
4418f4
if ($genreq_mode && $renew && !$nss) {
4418f4
print STDERR <
4418f4
Certificate renewal from PEM files is not yet supported.
4418f4
EOH
4418f4
}
4418f4
4418f4
$skip_random = $test_mode;
4418f4
$overwrite_key = $test_mode;
4418f4
$servername = $ARGV[0];
4418f4
$randfile = $ssltop."/.rand.".$$;
4418f4
$keyEncPassword = '';  # for the one we write
4418f4
$tmpPasswordFile = ''; # none has been created yet
4418f4
$keyfile = $ssltop."/private/".$servername.".key";
4418f4
if ($ca_mode) {
4418f4
    $keyfile = $cadir."/private/".$servername.".key";
4418f4
}
4418f4
4418f4
### State variables
4418f4
my $bits = 0;
4418f4
my $myca = "Other";
4418f4
my $useca = 0;
4418f4
my $subject;
4418f4
#
4418f4
4418f4
Newt::Init();
4418f4
InitRoot(1);
4418f4
4418f4
local $SIG{__DIE__} = sub { @err=@_; Newt::Finished(); die @err;};
4418f4
4418f4
# Either mod_nss or mod_ssl is required
4418f4
requireModule();
4418f4
4418f4
# For mod_nss we need these variables set
4418f4
if ($nss) {
4418f4
    # the configuration file is required
4418f4
    if (!nssconfigFound()) {
4418f4
        Newt::newtWinMessage("Error", "Close", 
4418f4
        "Could not find mod_nss's nss.conf file".
4418f4
        "for this host:\n\nPress return to exit");
4418f4
        Newt::Finished();
4418f4
        exit 1;
4418f4
    }
4418f4
    
4418f4
    $modNssDbDir = getModNSSDatabase();
4418f4
    $nssNickname = $servername ? $servername : getNSSNickname();
4418f4
    $nssDBPrefix = getNSSDBPrefix();
4418f4
}
4418f4
4418f4
#
4418f4
# Does the key already exist? don't overwrite
4418f4
#
4418f4
4418f4
if (!$nss) {
4418f4
    if (!$genreq_mode && -f $keyfile && !$overwrite_key) {
4418f4
        Newt::newtWinMessage("Error", "Close", 
4418f4
		"You already have a key file for this host in file:\n\n" .
4418f4
		$keyfile . "\n\n" .
4418f4
		"This script will not overwrite an existing key.\n" . 
4418f4
		"You will need to remove or rename this file in order to" .
4418f4
		"generate a new key for this host, then rerun the command");
4418f4
        Newt::Finished();
4418f4
        exit 1;
4418f4
    }
4418f4
} else {
4418f4
    # check for the key in the database
4418f4
    if (!$genreq_mode && keyInDatabase($nssNickname,$modNssDbDir) &&
4418f4
        !$renew && !$overwrite_key) {
4418f4
        Newt::newtWinMessage("Error", "Close", 
4418f4
		    "You already have a key file for this host in the datatabase:\n\n" .
4418f4
		    "$modNssDbDir" ." with nickname ". "$nssNickname" . "\n\n" .
4418f4
		    "This script will not overwrite an existing key.\n" . 
4418f4
		    "You will need to remove or rename the database in order to" .
4418f4
		    "generate a new key for this host, then rerun the command");
4418f4
        Newt::Finished();
4418f4
       exit 1;
4418f4
    }
4418f4
}
4418f4
4418f4
######################################################################
4418f4
# Main
4418f4
#
4418f4
4418f4
# Array of windows which we cycle through. Each window function should
4418f4
# return: 
4418f4
#   "Next" or "Skip" -> go on to the next window
4418f4
#   "Back" -> go back to the last window which returned "Next"
4418f4
#   "Cancel" -> cancelled: quit and return failure.
4418f4
#
4418f4
# "Skip" is to allow for windows which don't display anything (due
4418f4
# to choices made in previous windows, for instance).
4418f4
#
4418f4
my @windows;
4418f4
if ($genreq_mode) {
4418f4
    $useca = 1;
4418f4
    @windows = $renew 
4418f4
        ? (passwordWindow,genReqWindow,) 
4418f4
        : (getkeysizeWindow,
4418f4
           customKeySizeWindow,
4418f4
           getRandomDataWindow,
4418f4
           passwordWindow,
4418f4
           genReqWindow,
4418f4
           );
4418f4
    $doingwhat="CSR generation";
4418f4
} elsif ($ca_mode) {
4418f4
    @windows = (CAwelcomeWindow,
4418f4
		getkeysizeWindow,
4418f4
		customKeySizeWindow,
4418f4
		getRandomDataWindow,
4418f4
		passwordWindow,
4418f4
		genCACertWindow,
4418f4
		);
4418f4
    $doingwhat="CA cert generation";
4418f4
} else {
4418f4
    @windows = (welcomeWindow,
4418f4
		getkeysizeWindow,
4418f4
		customKeySizeWindow,
4418f4
		getRandomDataWindow,
4418f4
		wantCAWindow,
4418f4
		passwordWindow,
4418f4
		genReqWindow,
4418f4
        genCertWindow,
4418f4
        ### @EXTRA@ ### Leave this comment here.
4418f4
        );
4418f4
    $doingwhat="testing CSR and cert generation";
4418f4
}
4418f4
4418f4
my $screen = 0;
4418f4
4418f4
my @screenstack;
4418f4
4418f4
my $result;
4418f4
4418f4
while ($screen <= $#windows) {
4418f4
    $result = $windows[$screen]->();
4418f4
    print STDERR "undef from window #" .$screen . "\n" if (!$result);
4418f4
    if ($result eq "Cancel") {
4418f4
	my $panel = Newt::Panel(1, 2, "Confirm");
4418f4
4418f4
	$panel->Add(0, 0, 
4418f4
		  Newt::TextboxReflowed(60, 10, 10, 0, 
4418f4
					"Do you want to cancel ".$doingwhat.
4418f4
					"?"));
4418f4
4418f4
	$panel->Add(0, 1, DoubleButton("Yes", "No"));
4418f4
	# Default to NOT cancel if escape is pressed (again)
4418f4
	$ret = &RunForm($panel, "No", "No");
4418f4
4418f4
	$panel->Hide();
4418f4
	undef $panel;
4418f4
4418f4
	last if $ret eq "Yes";
4418f4
	next;
4418f4
    }
4418f4
4418f4
    $nextscreen = $screen + 1 if ($result eq "Next" or $result eq "Skip"
4418f4
				  or !$result);
4418f4
    $nextscreen = pop @screenstack if ($result eq "Back" and scalar(@screenstack));
4418f4
    push @screenstack, $screen if ($result eq "Next");
4418f4
    $screen = $nextscreen;
4418f4
}
4418f4
4418f4
# Exit
4418f4
clearSensitiveData();
4418f4
Newt::Finished();
4418f4
exit 1 if ($result eq "Cancel");
4418f4
exit 0;
4418f4
4418f4
#
4418f4
# end main
4418f4
#
4418f4
4418f4
######################################################################
4418f4
# Handy functions
4418f4
4418f4
# Returns a panel containing two buttons of given names.
4418f4
sub DoubleButton {
4418f4
    my ($left, $right) = @_;
4418f4
    
4418f4
    my $leftb = Newt::Button($left)->Tag($left);
4418f4
    my $rightb = Newt::Button($right)->Tag($right);
4418f4
4418f4
    Newt::Panel(2, 1)
4418f4
      ->Add(0, 0, $leftb, Newt::NEWT_ANCHOR_RIGHT(), 0, 1, 0, 0)
4418f4
	  ->Add(1, 0, $rightb, Newt::NEWT_ANCHOR_LEFT(), 1, 1, 0, 0);
4418f4
}
4418f4
4418f4
# Returns a panel containing next/back/cancel buttons.
4418f4
sub NextBackCancelButton {
4418f4
    
4418f4
    my $nextb = Newt::Button('Next')->Tag('Next');
4418f4
    my $backb = Newt::Button('Back')->Tag('Back');
4418f4
    my $cancelb = Newt::Button('Cancel')->Tag('Cancel');
4418f4
4418f4
    Newt::Panel(3, 1)
4418f4
      ->Add(0, 0, $nextb, Newt::NEWT_ANCHOR_RIGHT(), 0, 1, 0, 0)
4418f4
	  ->Add(1, 0, $backb, Newt::NEWT_ANCHOR_RIGHT(), 1, 1, 0, 0)
4418f4
	      ->Add(2, 0, $cancelb, Newt::NEWT_ANCHOR_LEFT(), 1, 1, 0, 0);
4418f4
}
4418f4
4418f4
# Require that this Apache module (mod_nss or mod_ssl) be installed
4418f4
sub requireModule {
4418f4
4418f4
    my $module = $nss ? "mod_nss" : "mod_ssl";	
4418f4
    my $not_installed_msg = `rpm -q $module | grep "not installed"`;
4418f4
	
4418f4
	if ($not_installed_msg) {
4418f4
        Newt::newtWinMessage("Error", "Close", 
4418f4
        "$not_installed_msg".
4418f4
        "\nIt is required to generate this type of CSRs or certs".
4418f4
        "for this host:\n\nPress return to exit");
4418f4
        Newt::Finished();
4418f4
        exit 1;
4418f4
    }	
4418f4
}
4418f4
4418f4
# Check that nss.conf exists
4418f4
sub nssconfigFound {
4418f4
    # if it isn't in its usual place
4418f4
    if (!$nssconf || !(-f $nssconf)) {
4418f4
        # do an rpm query
4418f4
        my $cmd = 'rpm -ql mod_nss';
4418f4
        ($fh, $tmplist) = tempfile("list.XXXXXX");
4418f4
        system("$cmd > $tmplist");
4418f4
        $nssconf = `grep nss.conf $tmplist`;
4418f4
        unlink($tmplist);
4418f4
    }
4418f4
    return ($nssconf && (-f $nssconf));
4418f4
}
4418f4
4418f4
# Returns the mod_nss database directory path.
4418f4
sub getModNSSDatabase {
4418f4
   
4418f4
    # Extract the value from the mod_nss configuration file.
4418f4
    my $cmd ='/usr/bin/gawk \'/^NSSCertificateDatabase/ { print $2 }\'' . " $nssconf"; 
4418f4
    ($fh, $dbfile) = tempfile("dbdirectory.XXXXXX");
4418f4
    system("$cmd > $dbfile");
4418f4
    open(DIR, "<$dbfile");
4418f4
    my $dbdir = '';
4418f4
    chomp($dbdir = <DIR>);
4418f4
    
4418f4
    unlink($dbfile);
4418f4
    
4418f4
    return $dbdir;
4418f4
}
4418f4
4418f4
# Returns the rsa server name.
4418f4
sub getNSSNickname {
4418f4
4418f4
    # Extract the value from the mod_nss configuration file.
4418f4
    my $cmd ='/usr/bin/gawk \'/^NSSNickname/ { print $2 }\'' . " $nssconf";
4418f4
    ($fh, $nicknamefile) = tempfile("nssnickname.XXXXXX");
4418f4
    system("$cmd > $nicknamefile");
4418f4
    open(NICK, "<$nicknamefile");  
4418f4
    my $nickname = ''; 
4418f4
    chomp($nickname = <NICK>); 
4418f4
    unlink($nicknamefile);
4418f4
    return $nickname;
4418f4
}
4418f4
4418f4
# Returns the nss database prefix
4418f4
sub getNSSDBPrefix {
4418f4
4418f4
    # Extract the value from the mod_nss configuration file.
4418f4
    my $cmd ='/usr/bin/gawk \'/^NSSDBPrefix/ { print $2 }\'' . " $nssconf";
4418f4
    ($fh, $prefixfile) = tempfile("dbprefix.XXXXXX");
4418f4
    system("$cmd > $prefixfile");
4418f4
    open(PREFIX, "<$prefixfile");
4418f4
    my $prefix = '';
4418f4
    chomp($prefix = <PREFIX>); 
4418f4
    unlink($prefixfile);
4418f4
4418f4
    return $prefix;
4418f4
}
4418f4
4418f4
# Erases and deletes the password file
4418f4
sub clearSensitiveData {
4418f4
    if (-f $tmpPasswordFile) {
4418f4
       open(DOOMED,$tmpPasswordFile);
4418f4
       truncate(DOOMED,0);
4418f4
       close(DOOMED);
4418f4
       unlink($tmpPasswordFile);
4418f4
    }
4418f4
}
4418f4
4418f4
# Remove a directory and its contents
4418f4
sub removeDirectory {
4418f4
    my ($dir) = @_;
4418f4
    if (-f $dir) {
4418f4
        opendir(DOOMED, $dir) || die("Cannot open directory");
4418f4
        my @thefiles= readdir(DOOMED);
4418f4
        foreach my $file (@thefiles) {
4418f4
            unlink @file;
4418f4
        }
4418f4
        closedir(DOOMED);
4418f4
    	rmdir $dir;
4418f4
    }
4418f4
}
4418f4
4418f4
# Print error message
4418f4
sub printError {
4418f4
    my ($msg) = @_;
4418f4
    Newt::Suspend();
4418f4
    print STDERR "$msg\n";
4418f4
    Newt::Resume();
4418f4
}
4418f4
4418f4
# Is the given key in the database?
4418f4
sub keyInDatabase {
4418f4
    my ($nickname, $dbdir) = @_;
4418f4
    my $tmp = "tmp";
4418f4
    my $answer = `$bindir/certutil -L -d $dbdir | grep $nickname`;
4418f4
    return $answer;
4418f4
}
4418f4
4418f4
######################################################################
4418f4
# The window functions
4418f4
4418f4
sub makerand
4418f4
{
4418f4
    require Fcntl;
4418f4
4418f4
    my ($bits,$filename) = @_;
4418f4
4418f4
    my $count = 0;
4418f4
    
4418f4
    my @credits = ("This software contains the truerand library",
4418f4
		   "developed by Matt Blaze, Jim Reeds, and Jack",
4418f4
		   "Lacy. Copyright (c) 1992, 1994 AT&T.");
4418f4
    my ($cols, $rows) = Newt::GetScreenSize();
4418f4
    
4418f4
    foreach (@credits) {
4418f4
	$count++;
4418f4
	Newt::DrawRootText($cols-45, $rows-5 + $count, $_);
4418f4
    }
4418f4
4418f4
    $count = 0;
4418f4
    
4418f4
    my $panel = Newt::Panel(1, 2, "Generating random bits");
4418f4
    my $scale = Newt::Scale(40, $bits);
4418f4
4418f4
    $panel->Add(0, 0, Newt::Label("(this may take some time)"));
4418f4
4418f4
    $panel->Add(0, 1, $scale, 0, 0, 1);
4418f4
		
4418f4
    $panel->Draw();
4418f4
    
4418f4
    if (!sysopen($randfh,$filename,Fcntl::O_WRONLY()|Fcntl::O_CREAT()
4418f4
		 |Fcntl::O_TRUNC()|Fcntl::O_EXCL(),0600)) {
4418f4
	Newt::newtWinMessage("Error", "Close", 
4418f4
			     "Can't create random data file");
4418f4
	$panel->Hide();
4418f4
	undef $panel;
4418f4
	return "Cancel";
4418f4
    }
4418f4
4418f4
    Newt::Refresh();
4418f4
    while ($count++ < $bits/32) { 
4418f4
        use bytes; # random data is not UTF-8, prevent warnings
4418f4
	# decode as an "native-length" unsigned long
4418f4
	syswrite($randfh,pack("L!",Crypt::Makerand::trand32()));
4418f4
	$scale->Set($count*32);
4418f4
	Newt::Refresh();
4418f4
    }
4418f4
    $panel->Hide();
4418f4
    undef $panel;
4418f4
    close $randfh;
4418f4
}
4418f4
4418f4
sub getkeysizeWindow()
4418f4
{
4418f4
    $minbits = 512;
4418f4
    $maxbits = 8192;
4418f4
4418f4
    my $title= <
4418f4
Choose the size of your key. The smaller the key you choose the faster
4418f4
your server response will be, but you'll have less security. Keys of
4418f4
less than 1024 bits are easily cracked.
4418f4
4418f4
We suggest you select the default, 2048 bits.
4418f4
EOT
4418f4
    my $panel = Newt::Panel(1, 3, "Choose key size");
4418f4
    my $listbox = Newt::Listbox(5, 0);
4418f4
    my $text = Newt::Textbox(70, 6, 0, $title);
4418f4
    my @listitems = ("512 (insecure)",
4418f4
		     "1024 (low-grade, fast speed)",
4418f4
		     "2048 (medium-security, medium speed) [RECOMMENDED]",
4418f4
		     "4096 (high-security, slow speed)",
4418f4
		     "Choose your own");
4418f4
4418f4
    $listbox->Append(@listitems);
4418f4
    
4418f4
    $panel->Add(0, 0, $text);
4418f4
    $panel->Add(0, 1, $listbox, 0, 0, 1);
4418f4
    $panel->Add(0, 2, NextBackCancelButton());
4418f4
    
4418f4
    Newt::newtListboxSetCurrent($listbox->{co}, 2);
4418f4
4418f4
    $panel->Draw();
4418f4
4418f4
    $ret = &RunForm($panel);    
4418f4
4418f4
    if ($ret eq "Cancel" or $ret eq "Back") {
4418f4
	$panel->Hide();
4418f4
	undef $panel;
4418f4
	return $ret;
4418f4
    }
4418f4
    
4418f4
    $bits = 256;
4418f4
4418f4
    foreach $item(@listitems) {
4418f4
	$bits = $bits * 2;
4418f4
	if ($item eq $listbox->Get()) {
4418f4
	    last;
4418f4
	}
4418f4
    }
4418f4
4418f4
    $panel->Hide();
4418f4
    undef $panel;
4418f4
    return $ret;
4418f4
}
4418f4
4418f4
sub customKeySizeWindow()
4418f4
{
4418f4
    return "Next" if $bits < 8192; # else, choose custom size.
4418f4
4418f4
    Newt::Refresh();
4418f4
    
4418f4
    $bits = 0;
4418f4
4418f4
    $title = <
4418f4
Select the exact key size you want to use. Note that some browsers do
4418f4
not work correctly with arbitrary key sizes.  For a reasonable level
4418f4
of security you should use 2048.
4418f4
EOT
4418f4
4418f4
    $panel = Newt::Panel(1, 3, "Select exact key size");
4418f4
    my $entry = Newt::Entry(10, 0, "");
4418f4
4418f4
    $panel->Add(0, 0, Newt::Textbox(70, 4, 0, $title));
4418f4
    $panel->Add(0, 1, $entry);
4418f4
    $panel->Add(0, 2, NextBackCancelButton());
4418f4
    
4418f4
    do {
4418f4
	$panel->Focus($entry);
4418f4
4418f4
	$ret = &RunForm($panel);
4418f4
4418f4
	if ($ret eq "Cancel" or $ret eq "Back") {
4418f4
	    $panel->Hide();
4418f4
	    undef $panel;
4418f4
	    return $ret;
4418f4
	}
4418f4
4418f4
	if ($entry->Get() ne "") {
4418f4
	    $bits = int($entry->Get());
4418f4
	} else {
4418f4
	    $bits = 0;
4418f4
	}
4418f4
    } while ($bits < $minbits || $bits > $maxbits);
4418f4
    
4418f4
    $panel->Hide();
4418f4
    undef $panel;
4418f4
4418f4
    return "Next";
4418f4
}
4418f4
4418f4
sub welcomeWindow()
4418f4
{
4418f4
    my $name = $servername;
4418f4
    my $where_key = $nss
4418f4
        ? $modNssDbDir."/$nssDBPrefix"."key3.db" : "$ssltop/private/$name.key";
4418f4
    my $where_cert = $nss
4418f4
        ? $modNssDbDir."/$nssDBPrefix"."cert8.db" : "$ssltop/certs/$name.crt";
4418f4
    my $what = $nss ? "directory" : "file";
4418f4
    my $message = <
4418f4
You are now generating a new keypair which will be used to encrypt all
4418f4
SSL traffic to the server named $name. 
4418f4
Optionally you can also create a certificate request and send it to a
4418f4
certificate authority (CA) for signing.
4418f4
4418f4
The key will be stored in 
4418f4
    $where_key
4418f4
The certificate stored in 
4418f4
    $where_cert
4418f4
4418f4
If the key generation fails, move the $what
4418f4
    $where_key 
4418f4
to a backup location and try again.
4418f4
EOT
4418f4
4418f4
    my $panel = Newt::Panel(1, 2, "Keypair generation");
4418f4
    my $text = Newt::Textbox(70, 10, Newt::NEWT_TEXTBOX_SCROLL(), $message);
4418f4
    my $ret;
4418f4
4418f4
    $panel->Add(0, 0, $text);
4418f4
    $panel->Add(0, 1, DoubleButton("Next","Cancel"));
4418f4
4418f4
    $ret = &RunForm($panel);
4418f4
4418f4
    $panel->Hide();
4418f4
    undef $panel;
4418f4
4418f4
    return $ret;
4418f4
}
4418f4
4418f4
sub CAwelcomeWindow()
4418f4
{
4418f4
    my $name = $servername;
4418f4
    my $where = $nss ? $modNssDbDir."/$nssDBPrefix"."key3.db" : "$cadir/private/$name"; 
4418f4
    my $message = <
4418f4
You are now generating a new keypair which will be used for your
4418f4
private CA
4418f4
4418f4
The key will be stored in 
4418f4
    $where
4418f4
4418f4
If the key generation fails, move the file 
4418f4
    $where
4418f4
to a backup location and try again.
4418f4
EOT
4418f4
4418f4
    my $panel = Newt::Panel(1, 2, "CA Key generation");
4418f4
    my $text = Newt::Textbox(70, 10, Newt::NEWT_TEXTBOX_SCROLL(), $message);
4418f4
    my $ret;
4418f4
4418f4
    $panel->Add(0, 0, $text);
4418f4
    $panel->Add(0, 1, DoubleButton("Next","Cancel"));
4418f4
4418f4
    $ret = &RunForm($panel);
4418f4
4418f4
    $panel->Hide();
4418f4
    undef $panel;
4418f4
4418f4
    return $ret;
4418f4
}
4418f4
4418f4
sub wantCAWindow
4418f4
{
4418f4
    my $panel = Newt::Panel(1, 2, "Generate CSR");
4418f4
4418f4
    $panel->Add(0, 0, 
4418f4
	      Newt::TextboxReflowed(60, 10, 10, 0, 
4418f4
				    "Would you like to send a Certificate Request (CSR) " .
4418f4
				    "to a Certificate Authority (CA)?"));
4418f4
4418f4
    $panel->Add(0, 1, DoubleButton("Yes", "No"));
4418f4
4418f4
    $ret = &RunForm($panel);
4418f4
4418f4
    $panel->Hide();
4418f4
    undef $panel;
4418f4
4418f4
    if ($ret eq "Cancel") {
4418f4
	return "Cancel";
4418f4
    }
4418f4
4418f4
    $useca = ($ret eq "Yes") ? 1 : 0;
4418f4
4418f4
    return "Next";
4418f4
}
4418f4
4418f4
# Save the passphrase to a temporary file.
4418f4
sub savePassword 
4418f4
{
4418f4
    my ($passwd) = @_;
4418f4
    #
4418f4
    # Write password to a file with lines formatted as:
4418f4
    # NSS Certificate DB:access_passphrase
4418f4
    # PEM Token #0:ca_key_access_passphrase
4418f4
    # PEM Token #1:server_key_access_passphrase
4418f4
    #
4418f4
    my $passwordLine = $nss
4418f4
        ? "NSS Certificate DB" : $cacert ? "PEM Token #0:" : "PEM Token #1:";
4418f4
    $passwordLine .= "$passwd\n";
4418f4
    if ($tmpPasswordFile) {
4418f4
        # append to existing file
4418f4
        if (!open(SESAME, ">>$tmpPasswordFile")) {
4418f4
            Newt::newtWinMessage("Error", "Close",
4418f4
                "Unable to append passphrase to $tmpPasswordFile".
4418f4
			    "\n\nPress return to continue");
4418f4
	        return "Back";
4418f4
        }
4418f4
    } else {
4418f4
        # write to a new file
4418f4
        $tmpPasswordFile = ".passwordfile.".$$;
4418f4
        if (!open (SESAME, ">$tmpPasswordFile")) {
4418f4
            Newt::newtWinMessage("Error", "Close",
4418f4
                "Unable to save passphrase to $tmpPasswordFile".
4418f4
			    "\n\nPress return to continue");
4418f4
		    $tmpPasswordFile = ''; # mark it as never created
4418f4
	        return "Back";
4418f4
        }
4418f4
    }
4418f4
    print SESAME $passwordLine;
4418f4
    close(SESAME);
4418f4
    # This file will be deleted on program exit.
4418f4
4418f4
    return "Next";
4418f4
}
4418f4
4418f4
# Prompts for a module or key access password.
4418f4
# The argument indicates wheter the password is to
4418f4
# access the nss module access or for access to the key
4418f4
# to be loaded from a pem file into a PEM module token.
4418f4
sub moduleAccesPasswordWindow
4418f4
{
4418f4
    my ($what) = @_;
4418f4
    # either "module" or "key"
4418f4
4418f4
    my $message = <
4418f4
At this stage you can provide the $what acess passphrase.
4418f4
EOT
4418f4
    $panel = Newt::Panel(1, 3, $what." access");
4418f4
    $panel->Add(0, 0, Newt::Textbox(70, 5, 0, $message));
4418f4
4418f4
    my $checkbox = Newt::Checkbox($what." access password if any");
4418f4
    $panel->Add(0, 1, $checkbox);
4418f4
    $panel->Add(0, 2, NextBackCancelButton());
4418f4
4418f4
    $ret = &RunForm($panel);
4418f4
4418f4
    my $plain = 1;
4418f4
    $plain = 0 if $checkbox->Checked();
4418f4
4418f4
    $panel->Hide();
4418f4
    undef $panel;
4418f4
4418f4
    return $ret if ($ret eq "Back" or $ret eq "Cancel" or $plain == 1);
4418f4
 
4418f4
    $panel = Newt::Panel(1, 3, "Enter the $what passphrase");
4418f4
4418f4
    $message = <
4418f4
This is the passphrase to your $what.
4418f4
EOT
4418f4
    $panel->Add(0, 0, Newt::Textbox(70, 5, 0, $message));
4418f4
    $subp = Newt::Panel(2,2);
4418f4
    $entp1 = AddField($subp,0,"Passphrase","",30,0,
4418f4
                      Newt::NEWT_FLAG_HIDDEN());
4418f4
4418f4
    $panel->Add(0, 1, $subp, 0, 0, 1);
4418f4
    $panel->Add(0, 2, NextBackCancelButton());
4418f4
4418f4
    while (1) {
4418f4
        # Clear the password entry box to avoid confusion on looping
4418f4
        $entp1->Set("");
4418f4
	    $panel->Focus($entp1);
4418f4
4418f4
	    # Pass "Ignore" to make enter go to next widget.
4418f4
	    $ret = &RunForm($panel, "Ignore");
4418f4
4418f4
	    if ($ret eq "Cancel" or $ret eq "Back") {
4418f4
	        $panel->Hide();
4418f4
	        undef $subp;
4418f4
	        undef $panel;
4418f4
	        return $ret;
4418f4
	    }
4418f4
	    $pass1 = $entp1->Get();
4418f4
4418f4
	    last;
4418f4
    }
4418f4
4418f4
    $panel->Hide();
4418f4
    undef $panel;
4418f4
4418f4
    return $ret if ($ret eq "Back" or $ret eq "Cancel");
4418f4
4418f4
    # Save it to a temporary file to supply to the nss utilities,
4418f4
    # the file will be erased upon exit
4418f4
    savePassword($pass1);
4418f4
4418f4
    return "Next";
4418f4
	
4418f4
}
4418f4
4418f4
# Prompts for key encryption password 
4418f4
# When using NSS it prompts for the
4418f4
# module acces password instead.
4418f4
sub passwordWindow
4418f4
{
4418f4
    if ($nss || $renew) {
4418f4
        # nss module access password or key password
4418f4
        return moduleAccesPasswordWindow($nss ? "module" : "key");
4418f4
    }
4418f4
	
4418f4
    my $message = <
4418f4
At this stage you can set the passphrase on your private key. If you
4418f4
set the passphrase you will have to enter it every time the server
4418f4
starts.  The passphrase you use to encrypt your key must be the same
4418f4
for all the keys used by the same server installation.
4418f4
4418f4
If you do not encrypt your key, then if someone breaks into your
4418f4
server and grabs the file containing your key, they will be able to
4418f4
decrypt all communications to and from the server that were negotiated
4418f4
using that key. If your key is encrypted it would be much more
4418f4
work for someone to retrieve the private key.
4418f4
EOT
4418f4
    $panel = Newt::Panel(1, 3, "Protecting your private key");
4418f4
4418f4
    $panel->Add(0, 0, Newt::Textbox(70, 11, 0, $message));
4418f4
4418f4
    my $checkbox = Newt::Checkbox("Encrypt the private key");
4418f4
    $panel->Add(0, 1, $checkbox);
4418f4
4418f4
    $panel->Add(0, 2, NextBackCancelButton());
4418f4
4418f4
    $ret = &RunForm($panel);
4418f4
4418f4
    my $plain = 1;
4418f4
    $plain = 0 if $checkbox->Checked();
4418f4
4418f4
    $panel->Hide();
4418f4
    undef $panel;
4418f4
4418f4
    return $ret if ($ret eq "Back" or $ret eq "Cancel" or $plain == 1);
4418f4
 
4418f4
    $panel = Newt::Panel(1, 3, "Set private key passphrase");
4418f4
4418f4
    $message = <
4418f4
Now we are going to set the passphrase on the private key. This
4418f4
passphrase is used to encrypt your private key when it is stored
4418f4
on disk. You will have to type this passphrase when the server
4418f4
starts.
4418f4
4418f4
-- DO NOT LOSE THIS PASS PHRASE --
4418f4
4418f4
If you lose the pass phrase you will not be able to run the server
4418f4
with this private key. You will need to generate a new private/public
4418f4
key pair and request a new certificate from your certificate authority.
4418f4
EOT
4418f4
    $panel->Add(0, 0, Newt::Textbox(70, 11, 0, $message));
4418f4
    $subp = Newt::Panel(2,2);
4418f4
    $entp1 = AddField($subp,0,"Passphrase (>4 characters)","",30,0,
4418f4
                      Newt::NEWT_FLAG_HIDDEN());
4418f4
    $entp2 = AddField($subp,1,"Passphrase (again)        ","",30,0,
4418f4
                      Newt::NEWT_FLAG_HIDDEN());
4418f4
4418f4
    $panel->Add(0, 1, $subp, 0, 0, 1);
4418f4
    $panel->Add(0, 2, NextBackCancelButton());
4418f4
4418f4
    while (1) {
4418f4
        # Clear the password entry boxes to avoid confusion on looping
4418f4
        $entp1->Set("");
4418f4
        $entp2->Set("");
4418f4
4418f4
	$panel->Focus($entp1);
4418f4
4418f4
	# Pass "Ignore" to make enter go to next widget.
4418f4
	$ret = &RunForm($panel, "Ignore");
4418f4
4418f4
	if ($ret eq "Cancel" or $ret eq "Back") {
4418f4
	    $panel->Hide();
4418f4
	    undef $subp;
4418f4
	    undef $panel;
4418f4
	    return $ret;
4418f4
	}
4418f4
	$pass1 = $entp1->Get();
4418f4
	$pass2 = $entp2->Get();
4418f4
4418f4
	if ($pass1 ne $pass2) {
4418f4
	    Newt::newtWinMessage("Error", "Close",
4418f4
                                 "The passphrases you entered do not match.");
4418f4
	    next;
4418f4
	}
4418f4
	if (length($pass1)<4) {
4418f4
	    Newt::newtWinMessage("Error", "Close",
4418f4
			       "The passphrase must be at least 4 characters".
4418f4
			       "\n\nPress return to try again");
4418f4
	    next;
4418f4
	}
4418f4
	last;
4418f4
    }
4418f4
4418f4
    $panel->Hide();
4418f4
    undef $panel;
4418f4
4418f4
    return $ret if ($ret eq "Back" or $ret eq "Cancel");
4418f4
4418f4
    # FIXME: Ugly, should use perl system() correctly.
4418f4
    $pass1 =~ s/"/\\\"/g;
4418f4
    $keyEncPassword = "\"". $pass1. "\"";
4418f4
4418f4
    return "Next";
4418f4
}
4418f4
4418f4
#
4418f4
# Bottleneck routine to call the nss utilities.
4418f4
# Calls are bracketed by newt suspend and resume
4418f4
# enabling user interaction from the nss utilities
4418f4
# and trace messages to the console.
4418f4
#
4418f4
sub nssUtilCmd {
4418f4
    
4418f4
    my ($cmd, $args) = @_;
4418f4
4418f4
    Newt::Suspend();
4418f4
    print STDOUT "$cmd $args"."\n";
4418f4
    $! = '';
4418f4
    if ($gdb) {
4418f4
        system("gdb $cmd");
4418f4
    } else {
4418f4
        system("$cmd $args");
4418f4
        print STDERR "$cmd returned $!"."\n" if $!;
4418f4
    }
4418f4
    Newt::Resume();
4418f4
}
4418f4
4418f4
#
4418f4
# make a certificate using the database
4418f4
#
4418f4
sub makeCertNSS
4418f4
{
4418f4
    my ($certfile, # output
4418f4
        $subject, $days, $nickname,
4418f4
        $noisefile, $pwdfile) = @_;
4418f4
    
4418f4
    # If no days specified it's a ca so use 2 years
4418f4
    use integer;
4418f4
    my $months = $days / 30;      
4418f4
    my $trustargs = $ca_mode ? "CT,," : "u,,";
4418f4
    $trustargs = "\"" . $trustargs. "\"";
4418f4
    
4418f4
    my $args = "-S ";
4418f4
    $args .= "-n $nickname ";
4418f4
    $args .= "-s $subject "; 
4418f4
    $args .= "-x ";              ## self-signed
4418f4
    $args .= "-t $trustargs ";
4418f4
    $args .= "-k rsa ";
4418f4
    $args .= "-g $bits ";
4418f4
    $args .= "-v $months ";
4418f4
    $args .= "-a ";
4418f4
    $args .= "-f $pwdfile " if $pwdfile;
4418f4
    $args .= "-z $noisefile " if $noisefile;
4418f4
    $args .= "-d $modNssDbDir "; 
4418f4
    $args .= "-p $nssDBPrefix " if $nssDBPrefix;
4418f4
    $args .= "-o $certfile " if $certfile;
4418f4
    
4418f4
    nssUtilCmd("$bindir/certutil", $args);
4418f4
4418f4
    if ($noisefile) {
4418f4
        unlink($noisefile);
4418f4
        $noisefile = '';
4418f4
    }
4418f4
    
4418f4
    if ($certfile && !-f $certfile) {
4418f4
        Newt::newtWinMessage("Error", "Close", 
4418f4
			     "Was not able to create a certificate for this ".
4418f4
			     "host:\n\nPress return to exit");
4418f4
        Newt::Finished();
4418f4
        exit 1;
4418f4
    }
4418f4
}
4418f4
4418f4
# Create a certificate-signing request file that can be submitted to 
4418f4
# a Certificate Authority for processing into a finished certificate.
4418f4
sub genRequestNSS 
4418f4
{
4418f4
    my ($csrfile, # output
4418f4
        $subject, $days, $noisefile, $pwdfile) = @_;
4418f4
    
4418f4
    use integer;
4418f4
    my $months = $days / 30;
4418f4
    
4418f4
    my $args = "-R ";
4418f4
    
4418f4
    $args .= "-s $subject ";
4418f4
    $args .= "-d $modNssDbDir ";
4418f4
    $args .= "-p $nssDBPrefix " if $nssDDPrefix;
4418f4
    $args .= "-a ";              ## using ascii 
4418f4
    $args .= "-k rsa ";
4418f4
    $args .= "-g $bits ";
4418f4
    $args .= "-f $pwdfile "   if $pwdfile;
4418f4
    $args .= "-v $months ";
4418f4
    $args .= "-z $noisefile " if $noisefile;
4418f4
    $args .= "-o $csrfile ";
4418f4
    
4418f4
    nssUtilCmd("$bindir/certutil", $args);
4418f4
4418f4
    if ($noisefile) {
4418f4
        unlink($noisefile);
4418f4
        $noisefile = '';
4418f4
    }
4418f4
    
4418f4
    if (!-f $csrfile) {
4418f4
        Newt::newtWinMessage("Error", "Close", 
4418f4
                 "Was not able to create a CSR for this ".
4418f4
                 "host:\n\nPress return to exit");
4418f4
        Newt::Finished();
4418f4
        exit 1; 
4418f4
    }
4418f4
}
4418f4
4418f4
# Generate a CA certificate file.
4418f4
# Use keyutil which supports exporting the key.
4418f4
sub makeCertOpenSSL
4418f4
{
4418f4
    my ($keyfile, $certfile, # output
4418f4
        $subject, $days, $noisefile, $pwdfile) = @_;
4418f4
4418f4
    use integer;
4418f4
    my $months = $days ? $days / 30 : 24;
4418f4
4418f4
    # build the arguments for a gen cert call, self-signed
4418f4
    my $args = "-c makecert ";
4418f4
    $args   .= "-g $bits ";
4418f4
    $args   .= "-s $subject ";
4418f4
    $args   .= "-v $months "; 
4418f4
    $args   .= "-a ";              ## using ascii 
4418f4
    $args   .= "-z $noisefile " if $noisefile;
4418f4
    $args   .= "-e $keyEncPassword " if $keyEncPassword; 
4418f4
              # there is no password when the
4418f4
              # user wants the key in the clear
4418f4
    $args   .= "-o $certfile ";
4418f4
    $args   .= "-k $keyfile";
4418f4
4418f4
    nssUtilCmd("$bindir/keyutil", $args);    
4418f4
4418f4
    if (!-f $certfile) {
4418f4
        Newt::newtWinMessage("Error", "Close", 
4418f4
                 "Was not able to create a certificate for this ".
4418f4
                 "host:\n\nPress return to exit");
4418f4
        unlink($noisefile) if $noisefile;
4418f4
        Newt::Finished();
4418f4
        exit 1;
4418f4
    }
4418f4
    if ($keyfile && (-f $keyfile)) {
4418f4
        if (chmod(0400, $keyfile) != 1) {
4418f4
            Newt::newtWinMessage("Error", "Close",
4418f4
                             "Could not set permissions of private key file.\n".
4418f4
                             "$keyfile");
4418f4
           Newt::Finished();
4418f4
           unlink($noisefile) if $noisefile;
4418f4
           exit 1;
4418f4
        }
4418f4
    }
4418f4
    if ($noisefile) {
4418f4
        unlink($noisefile);
4418f4
        $noisefile = '';
4418f4
    }
4418f4
}
4418f4
4418f4
# Create a certificate-signing request file that can be submitted to a 
4418f4
# Certificate Authority (CA) for processing into a finished certificate.
4418f4
# Use keyutil which exports key.
4418f4
sub genRequestOpenSSL
4418f4
{
4418f4
    my ($keyfile,$csrfile, # output
4418f4
        $subject,$days,$noisefile,$pwdfile) = @_;
4418f4
4418f4
    use integer;
4418f4
    my $months = $days ? $days / 30 : 24;
4418f4
    
4418f4
    # build the arguments for a gen request call
4418f4
    my $args = "-c genreq ";
4418f4
    $args   .= "-g $bits "; 
4418f4
    $args   .= "-s $subject ";
4418f4
    $args   .= "-v $months ";
4418f4
    $args   .= "-a ";              ## using ascii
4418f4
    $args   .= "-o $csrfile ";
4418f4
    $args   .= "-k $keyfile "; 
4418f4
    $args   .= "-e $keyEncPassword " if $keyEncPassword;
4418f4
              # there is no password when the
4418f4
              # user wants the key in the clear
4418f4
    $args   .= "-z $noisefile "  if $noisefile;
4418f4
 
4418f4
    nssUtilCmd("$bindir/keyutil", $args);
4418f4
         
4418f4
    if ($noisefile) {
4418f4
        unlink($noisefile);
4418f4
        $noisefile = '';
4418f4
    }
4418f4
    Newt::Resume();
4418f4
    
4418f4
    if (!-f $csrfile) {
4418f4
        Newt::newtWinMessage("Error", "Close", 
4418f4
                 "Unable to create a cert signing request for this ".
4418f4
                 "host:\n\nPress return to exit");
4418f4
        Newt::Finished();
4418f4
        exit 1;
4418f4
    }
4418f4
    if ($keyfile && !(-f $keyfile)) {
4418f4
        Newt::newtWinMessage("Error", "Close", 
4418f4
                 "Unable to create a key for this ".
4418f4
                 "host:\n\nPress return to exit");
4418f4
        Newt::Finished();
4418f4
        exit 1;
4418f4
    }
4418f4
    if (chmod(0400, $keyfile) != 1) {
4418f4
        Newt::newtWinMessage("Error", "Close",
4418f4
                 "Could not set permissions of private key file.\n".
4418f4
                 "$keyfile");
4418f4
        Newt::Finished();
4418f4
        exit 1;
4418f4
    }
4418f4
}
4418f4
4418f4
# Renew a certificate which is stored in the nss database
4418f4
sub renewCertNSS
4418f4
{
4418f4
    my ($csrfile, $dbdir, $dbprefix, $nickname, $days, $pwdfile) = @_;
4418f4
4418f4
    use integer;
4418f4
    my $months = $days ? $days / 30 : 24;
4418f4
    
4418f4
    # Build the arguments for a certificate renewal request
4418f4
    # This is a request where we reuse the existing key pair
4418f4
    
4418f4
    my $args = "-R ";
4418f4
    $args   .= "-d $dbdir ";
4418f4
    $args   .= "-p $dbprefix " if $dbprefix;
4418f4
    $args   .= "-a ";              ## using ascii 
4418f4
    $args   .= "-k $nickname ";    ## pass cert nickname as key id
4418f4
    $args   .= "-f $pwdfile "   if $pwdfile;
4418f4
    $args   .= "-v $months ";
4418f4
    $args   .= "-o $csrfile ";
4418f4
    
4418f4
    nssUtilCmd("$bindir/certutil", $args);
4418f4
    
4418f4
    if (!-f $csrfile) {
4418f4
        Newt::newtWinMessage("Error", "Close", 
4418f4
                 "Was not able to create a CSR for this ".
4418f4
                 "host:\n\nPress return to exit");
4418f4
        Newt::Finished();
4418f4
        exit 1; 
4418f4
    }
4418f4
}
4418f4
4418f4
# Renew a certificate which is stored in a PEM file
4418f4
sub renewCertOpenSSL
4418f4
{
4418f4
    my ($csrfile, # output
4418f4
        $certfile,$keyfile,$cacert,$days) = @_;
4418f4
4418f4
    use integer;
4418f4
    my $months = $days ? $days / 30 : 24;
4418f4
    
4418f4
    # Build the arguments for a certificate renewal request
4418f4
    # This is a request where we reuse the existing key pair
4418f4
4418f4
    my $args = "--command genreq ";
4418f4
    $args   .= "--ascii ";              ## using ascii
4418f4
    $args   .= "--renew $certfile "; 
4418f4
    $args   .= "--input $keyfile "; 
4418f4
    $args   .= "--cacert " if $cacert;
4418f4
    $args   .= "--filepwdnss $pwdfile " if $pwdfile;    
4418f4
    $args   .= "--validity $months "; 
4418f4
    $args   .= "--out $csrfile ";
4418f4
    ### pass $noisefile?
4418f4
4418f4
    nssUtilCmd("$bindir/keyutil", $args);
4418f4
         
4418f4
    Newt::Resume();
4418f4
    
4418f4
    if (!-f $csrfile) {
4418f4
        Newt::newtWinMessage("Error", "Close", 
4418f4
                 "Unable to create a cert signing request for this ".
4418f4
                 "host:\n\nPress return to exit");
4418f4
        Newt::Finished();
4418f4
        exit 1;
4418f4
    }
4418f4
}
4418f4
4418f4
sub AddField
4418f4
{
4418f4
    my ($panel, $row, $msg, $default, $width, $topspace, $flags) = (@_, 0, 0);
4418f4
    my $entry;
4418f4
4418f4
    $panel->Add(0, $row, Newt::Label($msg), Newt::NEWT_ANCHOR_RIGHT(), 0, $topspace);
4418f4
    $entry = Newt::Entry($width, $flags, $default);
4418f4
    $panel->Add(1, $row, $entry, Newt::NEWT_ANCHOR_LEFT(), 1, $topspace);
4418f4
4418f4
    $entry;
4418f4
}
4418f4
4418f4
sub getCertDetails
4418f4
{
4418f4
    my ($fqdn, $msg, $iscsr) = (@_, 0);
4418f4
    my $cert;
4418f4
    my $panel;
4418f4
    my $subp;
4418f4
4418f4
    my $ents = {}, $cert = {};
4418f4
4418f4
    $panel = Newt::Panel(1, 3, "Enter details for your certificate");
4418f4
4418f4
    $panel->Add(0, 0, Newt::TextboxReflowed(65, 10, 10, 0, $msg));
4418f4
    
4418f4
    if ($iscsr) {
4418f4
	$subp = Newt::Panel(2, 9);
4418f4
    } else {
4418f4
	$subp = Newt::Panel(2, 6);
4418f4
    }
4418f4
4418f4
    $ents{'C'} = AddField($subp, 0, "Country Name (ISO 2 letter code)", "GB", 3);
4418f4
    $ents{'ST'} = AddField($subp, 1, 
4418f4
			   "State or Province Name (full name)", "Berkshire", 20, 0,
4418f4
			  Newt::NEWT_ENTRY_SCROLL());
4418f4
    $ents{'L'} = AddField($subp, 2, "Locality Name (e.g. city)", "Newbury", 20, 0, 
4418f4
			  Newt::NEWT_ENTRY_SCROLL());
4418f4
    $ents{'O'} = AddField($subp, 3, 
4418f4
			  "Organization Name (eg, company)", "My Company Ltd", 30, 0,
4418f4
			  Newt::NEWT_ENTRY_SCROLL());
4418f4
    $ents{'OU'} = AddField($subp, 4, "Organizational Unit Name (eg, section)", "", 30, 0,
4418f4
			   Newt::NEWT_ENTRY_SCROLL());
4418f4
    $ents{'CN'} = AddField($subp, 5, 
4418f4
			   "Common Name (fully qualified domain name)", $fqdn, 30, 1, 
4418f4
			   Newt::NEWT_ENTRY_SCROLL());
4418f4
4418f4
    if ($iscsr) {
4418f4
4418f4
	my $msg = "Extra attributes for certificate request:";
4418f4
4418f4
	$subp->Add(0, 6, Newt::Textbox(length($msg), 1, 0, $msg),
4418f4
		   Newt::NEWT_ANCHOR_RIGHT());
4418f4
4418f4
	$ents{'Challenge'} = AddField($subp, 7, "Optional challenge password",
4418f4
				      "", 20, 0);
4418f4
	$ents{'CompanyName'} = AddField($subp, 8, "Optional company name", "", 30, 0,
4418f4
			  Newt::NEWT_ENTRY_SCROLL());
4418f4
    }
4418f4
4418f4
    $panel->Add(0, 1, $subp, 0, 0, 1);
4418f4
4418f4
    $panel->Add(0, 2, NextBackCancelButton(), 0, 0, 0, 0, -1);
4418f4
4418f4
    while (1) {
4418f4
	
4418f4
	# Pass "Ignore" to make enter go to next widget.
4418f4
	$ret = &RunForm($panel, "Ignore");
4418f4
4418f4
	if ($ret eq "Next" && $iscsr) {
4418f4
	    my $pass = $ents{'Challenge'}->Get();
4418f4
	    if (length($pass) > 0 && length($pass) < 4) {
4418f4
		Newt::newtWinMessage("Error", "Retry",
4418f4
				     "The challenge password must be at least four characters in length");
4418f4
		# Move focus to challenge password field
4418f4
		$panel->Focus($ents{'Challenge'});
4418f4
		# and go again.
4418f4
		next;
4418f4
	    }
4418f4
	}
4418f4
	last;
4418f4
    }
4418f4
4418f4
    if ($ret eq "Cancel" or $ret eq "Back") {
4418f4
	$panel->Hide();
4418f4
	undef $subp;
4418f4
	undef $panel;
4418f4
	return $ret;
4418f4
    }
4418f4
4418f4
    $cert{'C'} = $ents{'C'}->Get();
4418f4
    $cert{'ST'} = $ents{'ST'}->Get();
4418f4
    $cert{'L'} = $ents{'L'}->Get();
4418f4
    $cert{'O'} = $ents{'O'}->Get();
4418f4
    $cert{'OU'} = $ents{'OU'}->Get();
4418f4
    $cert{'CN'} = $ents{'CN'}->Get();
4418f4
4418f4
    # Escape commas
4418f4
    foreach my $part (keys %cert) {
4418f4
        $cert{$part} =~ s/,/\\\\,/g;
4418f4
    }
4418f4
4418f4
    # Build the subject from the details
4418f4
    
4418f4
    $SEP     = ", ";
4418f4
    $subject = 'CN' . "=" . $cert{'CN'};
4418f4
    $subject = $subject . $SEP . 'OU' . "=" . $cert{'OU'} if $cert{'OU'};
4418f4
    $subject = $subject . $SEP . 'O'  . "=" . $cert{'O'}  if $cert{'O'};
4418f4
    $subject = $subject . $SEP . 'L'  . "=" . $cert{'L'}  if $cert{'L'};
4418f4
    $subject = $subject . $SEP . 'ST' . "=" . $cert{'ST'} if $cert{'ST'};
4418f4
    $subject = $subject . $SEP . 'C'  . "=" . $cert{'C'}  if $cert{'C'};
4418f4
    
4418f4
    if ($iscsr) {
4418f4
    $cert{'CompanyName'} = $ents{'CompanyName'}->Get();
4418f4
    $cert{'Challenge'} = $ents{'Challenge'}->Get();
4418f4
    $subject = $subject . $SEP . 'CompanyName' ."=" . $cert{'CompanyName'} if $cert{'CompanyName'};
4418f4
    $subject = $subject . $SEP . 'Challenge' ."=" . $cert{'Challenge'} if $cert{'Challenge'};
4418f4
    }
4418f4
4418f4
    $panel->Hide();
4418f4
4418f4
    undef $subp;
4418f4
    undef $panel;
4418f4
4418f4
    # must escape the double quotes because
4418f4
    # it will be embedded in another string
4418f4
    $subject = "\"" . "$subject" . "\"";
4418f4
	
4418f4
    return "Next";
4418f4
}
4418f4
4418f4
sub whichCAWindow {
4418f4
    return "Skip" unless $useca;
4418f4
4418f4
    my $title = <
4418f4
Please choose the Certificate Authority you wish to send
4418f4
your certificate request to
4418f4
EOT
4418f4
    my $panel = Newt::Panel(1, 3, "Choose Certificate Authority");
4418f4
    my $listbox = Newt::Listbox(4, 0);
4418f4
    my $text = Newt::Textbox(60, 2, 0, $title);
4418f4
    my @listitems = ("Equifax","Thawte","VeriSign","Other");
4418f4
    undef $myca;
4418f4
4418f4
    $listbox->Append(@listitems);
4418f4
    
4418f4
    $panel->Add(0, 0, $text);
4418f4
    $panel->Add(0, 1, $listbox, 0, 0, 1);
4418f4
    if ($genreq_mode) {
4418f4
	$panel->Add(0, 2, DoubleButton("Next","Cancel"));
4418f4
    } else {
4418f4
	$panel->Add(0, 2, NextBackCancelButton());
4418f4
    }
4418f4
4418f4
    Newt::newtListboxSetCurrent($listbox->{co}, 0);
4418f4
4418f4
    $panel->Draw();
4418f4
    $ret = &RunForm($panel);
4418f4
4418f4
    $myca = $listbox->Get();
4418f4
4418f4
    $panel->Hide();
4418f4
    undef $panel;
4418f4
    Newt::Refresh();
4418f4
    return $ret;
4418f4
}
4418f4
4418f4
# Cert signing request generation for renewal
4418f4
sub renewCert
4418f4
{
4418f4
    my ($csrfile) = @_;
4418f4
4418f4
    my $tempDbDir = "/tmp/nss.".$$;
4418f4
4418f4
    # Get a comfirmation
4418f4
    my $msg = "You are about to issue a certificate renewal";
4418f4
    my $panel = Newt::Panel(1, 2, "Certificate Renewal");
4418f4
    $panel->Add(0, 0, 
4418f4
            Newt::TextboxReflowed(60, 10, 10, 0, 
4418f4
            "Would you like to send a Certificate Request" .
4418f4
            "for\n\n$servername".
4418f4
            "\nto a Certificate Authority (CA)?"));
4418f4
4418f4
    $panel->Add(0, 1, DoubleButton("Yes", "No"));
4418f4
    $ret = &RunForm($panel);
4418f4
    $panel->Hide();
4418f4
    undef $panel;
4418f4
4418f4
    return "Cancel" if $ret eq "Cancel";
4418f4
   
4418f4
    # Cert to renew could be in the nss database or in a pem file
4418f4
4418f4
    if ($nss) {
4418f4
        # Renew cert in the nss database
4418f4
        renewCertNSS($csrfile, $modNssDbDir, $nssDBPrefix, 
4418f4
                     $nssNickname, $days, $tmpPasswordFile);
4418f4
    } else {
4418f4
        # Renew cert in a PEM file
4418f4
        renewCertOpenSSL($csrfile, $certfile, $keyfile, $cacert, $days);
4418f4
    }
4418f4
}
4418f4
4418f4
sub genReqWindow
4418f4
{
4418f4
    return "Skip" unless $useca;
4418f4
4418f4
    $keyfile = $ssltop."/private/".$servername.".key";
4418f4
    $certfile = $ssltop."/certs/".$servername.".crt";
4418f4
    
4418f4
    $num = 0;
4418f4
    while (-f $ssltop."/certs/".$servername.".$num.csr") {
4418f4
	$num++;
4418f4
    }
4418f4
    $csrfile = $ssltop."/certs/".$servername.".$num.csr";
4418f4
    
4418f4
    return renewCert($csrfile) if $renew;
4418f4
    
4418f4
    my $msg = "You are about to be asked to enter information that will be ".
4418f4
	"incorporated into your certificate request to a CA. What you are about to ".
4418f4
        "enter is what is called a Distinguished Name or a DN.  There are ".
4418f4
        "quite a few fields but you can leave some blank.";
4418f4
4418f4
    my $ret = getCertDetails($servername,$msg, 1);
4418f4
    return $ret unless ($ret eq "Next");
4418f4
4418f4
    if ($nss) {
4418f4
        genRequestNSS($csrfile, $subject, 730, $randfile, $tmpPasswordFile);
4418f4
    } else {
4418f4
        genRequestOpenSSL($keyfile, $csrfile,
4418f4
                          $subject, 730, $randfile, $tmpPasswordFile);
4418f4
    }
4418f4
4418f4
    # Now make a temporary cert; skip for OpenSSL since it would
4418f4
    # overwrite the existing key.
4418f4
    if (!$genreq_mode && !-f $certfile && $nss) {
4418f4
        makeCertNSS($certfile,
4418f4
                    $subject, $cert_days, $nssNickname,
4418f4
                    $randfile, $tmpPasswordFile);
4418f4
    }
4418f4
4418f4
    undef $csrtext;
4418f4
    open(CSR,"<$csrfile");
4418f4
    while(<CSR>) {
4418f4
	$csrtext .= $_;
4418f4
    }
4418f4
    close(CSR);
4418f4
4418f4
    # Fixme: Disabling csr display, not recognized as PEM base 64 encoded
4418f4
    $csrtext = "" if $renew && !$nss;
4418f4
4418f4
    Newt::Suspend();
4418f4
    
4418f4
    # Clear the screen
4418f4
    system("clear");
4418f4
4418f4
    if ($myca eq "VeriSign") {
4418f4
	
4418f4
	print <
4418f4
You now need to connect to the VeriSign site and submit your CSR. The
4418f4
page at https://digitalid.verisign.com/server/help/hlpEnrollServer.htm
4418f4
explains how to do this, and what additional documention will be
4418f4
required before VeriSign can sign your certificate.
4418f4
4418f4
Your CSR is given below. To submit it to VeriSign, go through the
4418f4
enrollment process starting at
4418f4
https://digitalid.verisign.com/server/enrollIntro.htm. Paste the CSR,
4418f4
including the BEGIN and END lines, when prompted in step 4.
4418f4
4418f4
$csrtext
4418f4
EOT
4418f4
}
4418f4
4418f4
    if ($myca eq "Thawte") {
4418f4
	print <
4418f4
You now need to connect to the Thawte site and submit your CSR. The
4418f4
page at https://www.thawte.com/certs/server/request.html explains how
4418f4
to do this, and what additional documention will be required before
4418f4
Thawte can sign your certificate.
4418f4
4418f4
Your CSR is given below. To submit it to Thawte, go to
4418f4
https://www.thawte.com/cgi/server/step1.exe and select "Web Server
4418f4
Certificate". Paste the CSR, including the BEGIN and END lines, when
4418f4
prompted.
4418f4
4418f4
$csrtext
4418f4
EOT
4418f4
}
4418f4
4418f4
    if ($myca eq "Equifax") {
4418f4
	print <
4418f4
You now need to connect to the Equifax site and submit your CSR. The
4418f4
page at http://www.equifaxsecure.com/ebusinessid/c2net/ explains how
4418f4
to do this, and what additional documention will be required before
4418f4
Equifax can sign your certificate.
4418f4
4418f4
Your CSR is given below. To submit it to Equifax, go to
4418f4
http://www.equifaxsecure.com/ebusinessid/c2net/
4418f4
Paste the CSR, including the BEGIN and END lines, when prompted.
4418f4
4418f4
$csrtext
4418f4
EOT
4418f4
}
4418f4
4418f4
    if ($myca eq "Other") {
4418f4
	print <
4418f4
You now need to submit your CSR and documentation to your certificate
4418f4
authority. Submitting your CSR may involve pasting it into an online
4418f4
web form, or mailing it to a specific address. In either case, you
4418f4
should include the BEGIN and END lines.
4418f4
4418f4
$csrtext
4418f4
EOT
4418f4
}
4418f4
4418f4
    print <
4418f4
    
4418f4
A copy of this CSR has been saved in the file
4418f4
$csrfile
4418f4
4418f4
Press return when ready to continue
4418f4
EOT
4418f4
    $_=<STDIN>;
4418f4
    Newt::Resume();
4418f4
    return "Next";
4418f4
}
4418f4
4418f4
4418f4
sub genCertWindow
4418f4
{
4418f4
    return "Skip" if $useca;
4418f4
4418f4
    $keyfile = $ssltop."/private/".$servername.".key";
4418f4
    $certfile = $ssltop."/certs/".$servername.".crt";
4418f4
    
4418f4
    my $msg = "You are about to be asked to enter information that will be ".
4418f4
	"made into a self-signed certificate for your server. What you are ".
4418f4
	"about to ".
4418f4
	"enter is what is called a Distinguished Name or a DN.  There are ".
4418f4
	"quite a few fields but you can leave some blank";
4418f4
4418f4
    my $ret = getCertDetails($servername,$msg, 0);
4418f4
    return $ret unless ($ret eq "Next");
4418f4
4418f4
    if ($nss) {
4418f4
        makeCertNSS($certfile, # output
4418f4
            $subject,$cert_days,$nssNickname,
4418f4
            $randfile,$tmpPasswordFile);
4418f4
    } else {
4418f4
        makeCertOpenSSL($keyfile,$certfile, # output
4418f4
            $subject,$cert_days,
4418f4
            $randfile,$tmpPasswordFile);
4418f4
    }
4418f4
4418f4
    return "Next";
4418f4
}
4418f4
4418f4
sub genCACertWindow
4418f4
{
4418f4
    return "Skip" if $useca;
4418f4
4418f4
    $keyfile = $cadir."/private/".$servername;
4418f4
    $certfile = $cadir."/".$servername;
4418f4
    
4418f4
    my $msg = "You are about to be asked to enter information that will be ".
4418f4
	"made into a certificate for your CA key. What you are ".
4418f4
	"about to ".
4418f4
	"enter is what is called a Distinguished Name or a DN.  There are ".
4418f4
	"quite a few fields but you can leave some blank";
4418f4
4418f4
    my $ret = getCertDetails("",$msg, 0);
4418f4
    return $ret unless ($ret eq "Next");
4418f4
4418f4
    if ($nss) {
4418f4
        makeCertNSS('',$subject,730,$nssNickname,
4418f4
                    $randfile,$tmpPasswordFile);
4418f4
    } else {
4418f4
        makeCertOpenSSL($keyfile,$certfile,$subject,730,
4418f4
                        $randfile,$tmpPasswordFile);
4418f4
    }
4418f4
4418f4
    return "Next";
4418f4
}
4418f4
4418f4
sub getRandomDataWindow() 
4418f4
{
4418f4
    my $randbits = $bits * 2;
4418f4
4418f4
# Get some random data from truerand library
4418f4
#
4418f4
    if (!$skip_random) {
4418f4
	FinishRoot();
4418f4
	InitRoot(0);
4418f4
	makerand($randbits,$randfile);
4418f4
	FinishRoot();
4418f4
4418f4
# Get some random data from keystrokes
4418f4
#
4418f4
      Newt::Suspend();
4418f4
4418f4
      system("$bindir/keyrand $randbits $randfile");
4418f4
4418f4
      Newt::Resume();
4418f4
    } else {
4418f4
# No extra random seed is being provided to nss. Rely
4418f4
# on nss faster autoseeding process. The nss utilities
4418f4
# will prompt the user for some keystrokes.
4418f4
    $randfile = '';
4418f4
    }
4418f4
    return "Next";
4418f4
}