2012-05-07 20:56:09 +02:00
|
|
|
#!/usr/bin/perl
|
|
|
|
|
|
|
|
use strict;
|
2012-04-08 02:11:16 +02:00
|
|
|
use warnings;
|
|
|
|
|
2015-01-28 19:23:03 +01:00
|
|
|
# create TLS certificates for qpsmtpd
|
2006-01-05 03:12:46 +01:00
|
|
|
use File::Temp qw/ tempfile tempdir /;
|
|
|
|
use Getopt::Long;
|
2015-01-28 19:23:03 +01:00
|
|
|
use Sys::Hostname;
|
2006-01-05 03:12:46 +01:00
|
|
|
|
|
|
|
my %opts = ();
|
2015-01-28 19:23:03 +01:00
|
|
|
my $hostname = hostname();
|
2008-03-13 20:51:00 +01:00
|
|
|
print "Using hostname: $hostname\n";
|
2006-01-05 03:12:46 +01:00
|
|
|
my %defaults = (
|
|
|
|
C => 'XY',
|
|
|
|
ST => 'unknown',
|
|
|
|
L => 'unknown',
|
|
|
|
O => 'QSMTPD',
|
|
|
|
OU => 'Server',
|
|
|
|
CN => $hostname,
|
|
|
|
);
|
|
|
|
|
|
|
|
GetOptions(\%opts,
|
|
|
|
'C|Country:s',
|
|
|
|
'ST|State:s',
|
|
|
|
'L|Locality|City:s',
|
|
|
|
'O|Organization:s',
|
|
|
|
'OU|OrganizationalUnit|U:s',
|
|
|
|
'CN|CommonName|N:s',
|
|
|
|
'emailAddress|email|E:s',
|
|
|
|
'help|H',
|
|
|
|
);
|
|
|
|
|
|
|
|
usage() if $opts{help};
|
|
|
|
|
|
|
|
# initialize defaults
|
|
|
|
foreach my $key ( keys %defaults ) {
|
|
|
|
$opts{$key} = $defaults{$key} unless $opts{$key}
|
|
|
|
}
|
|
|
|
$opts{emailAddress} = 'postmaster@'.$opts{CN};
|
|
|
|
|
2014-11-11 01:26:46 +01:00
|
|
|
mkdir 'ssl' if ! -d 'ssl';
|
2006-01-05 03:12:46 +01:00
|
|
|
|
|
|
|
my $CA_key = 'ssl/qpsmtpd-ca.key';
|
|
|
|
my $CA_crt = 'ssl/qpsmtpd-ca.crt';
|
|
|
|
my $CA_serial = 'ssl/.cert.serial';
|
|
|
|
|
2012-05-07 20:56:09 +02:00
|
|
|
my $template;
|
2006-01-05 03:12:46 +01:00
|
|
|
my ($CA, $CAfilename) = tempfile( $template, DIR => "ssl", UNLINK => 1);
|
|
|
|
|
|
|
|
print ${CA} return_cfg('CA');
|
|
|
|
close ${CA};
|
|
|
|
|
|
|
|
system('openssl', 'genrsa', '-out', $CA_key, 2048) == 0
|
|
|
|
or die "Cannot create CA key: $?";
|
|
|
|
|
|
|
|
system('openssl', 'req', '-config', $CAfilename, '-new', '-x509',
|
|
|
|
'-days', (365*6), '-key', $CA_key,
|
|
|
|
'-out', $CA_crt) == 0
|
|
|
|
or die "Cannot create CA cert: $?";
|
|
|
|
|
|
|
|
my $SERVER_key = 'ssl/qpsmtpd-server.key';
|
|
|
|
my $SERVER_csr = 'ssl/qpsmtpd-server.csr';
|
|
|
|
my $SERVER_crt = 'ssl/qpsmtpd-server.crt';
|
2015-02-02 11:36:51 +01:00
|
|
|
my $SERVER_dhparam = 'ssl/qpsmtpd-dhparam.pem';
|
2006-01-05 03:12:46 +01:00
|
|
|
|
|
|
|
my ($SERVER, $SERVERfilename) = tempfile( $template, DIR => "ssl", UNLINK => 1);
|
|
|
|
print ${SERVER} return_cfg($opts{OU});
|
|
|
|
close ${SERVER};
|
|
|
|
|
|
|
|
system('openssl', 'genrsa', '-out', $SERVER_key, 1024) == 0
|
|
|
|
or die "Cannot create server key: $?";
|
|
|
|
|
|
|
|
system('openssl', 'req', '-config', $SERVERfilename, '-new',
|
|
|
|
'-key', $SERVER_key, '-out', $SERVER_csr) == 0
|
2006-02-05 02:28:44 +01:00
|
|
|
or die "Cannot create server cert: $?";
|
2006-01-05 03:12:46 +01:00
|
|
|
|
|
|
|
my ($SIGN, $SIGNfilename) = tempfile( $template, DIR => "ssl", UNLINK => 1);
|
|
|
|
print ${SIGN} <<"EOT";
|
|
|
|
extensions = x509v3
|
|
|
|
[ x509v3 ]
|
|
|
|
subjectAltName = email:copy
|
|
|
|
nsComment = tls certificate
|
|
|
|
nsCertType = server
|
|
|
|
EOT
|
|
|
|
close ${SIGN};
|
|
|
|
|
|
|
|
open my $SERIAL, '>', $CA_serial;
|
|
|
|
print ${SERIAL} "01\n";
|
|
|
|
close ${SERIAL};
|
|
|
|
|
|
|
|
system('openssl', 'x509', '-extfile', $SIGNfilename, '-days', (365*2),
|
|
|
|
'-CAserial', $CA_serial, '-CA', $CA_crt,
|
|
|
|
'-CAkey', $CA_key, '-in', $SERVER_csr,
|
|
|
|
'-req', '-out', $SERVER_crt) == 0
|
|
|
|
or die "Cannot sign cert: $?";
|
|
|
|
|
2015-02-02 20:48:39 +01:00
|
|
|
system('openssl', 'dhparam', '-out', $SERVER_dhparam, 2048) == 0
|
2015-02-02 10:55:40 +01:00
|
|
|
or die "Cannot create server dhparam: $?";
|
|
|
|
|
2006-01-05 03:12:46 +01:00
|
|
|
exit(0);
|
|
|
|
|
|
|
|
sub return_cfg {
|
|
|
|
my $OU = shift;
|
|
|
|
my $RANDOM = int(rand(1000)).'RAN'.int(rand(1000)).'DOM';
|
|
|
|
my $cfg = <<"EOT";
|
|
|
|
[ req ]
|
|
|
|
default_bits = 1024
|
|
|
|
default_keyfile = keyfile.pem
|
|
|
|
distinguished_name = req_distinguished_name
|
|
|
|
attributes = req_attributes
|
|
|
|
prompt = no
|
|
|
|
output_password = mypass
|
|
|
|
|
|
|
|
[ req_distinguished_name ]
|
|
|
|
C = $opts{C}
|
|
|
|
ST = $opts{ST}
|
|
|
|
L = $opts{L}
|
|
|
|
O = $opts{O}
|
|
|
|
OU = $OU
|
|
|
|
CN = $opts{CN}
|
|
|
|
emailAddress = $opts{emailAddress}
|
|
|
|
|
|
|
|
[ req_attributes ]
|
|
|
|
challengePassword = $RANDOM challenge password
|
|
|
|
EOT
|
|
|
|
return $cfg;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub usage {
|
|
|
|
print STDERR <<"EOT";
|
|
|
|
|
|
|
|
$0 will generate a TLS certificate "the quick way",
|
|
|
|
i.e. without interaction. You can change some defaults however.
|
|
|
|
|
|
|
|
These options are recognized: Default:
|
|
|
|
|
|
|
|
--C Country (two letters, e.g. DE) $defaults{C}
|
|
|
|
--ST State (spelled out) $defaults{ST}
|
|
|
|
--L City $defaults{L}
|
|
|
|
--O Organization $defaults{O}
|
|
|
|
--OU Organizational Unit $defaults{OU}
|
|
|
|
--CN Common name $defaults{CN}
|
|
|
|
--email Email address of postmaster postmaster\@CN
|
|
|
|
--help Show usage
|
|
|
|
|
|
|
|
EOT
|
|
|
|
exit(1);
|
|
|
|
}
|