version 1.2, 2019/01/01 04:55:00
|
version 1.3, 2019/07/08 23:00:16
|
Line 26
|
Line 26
|
# http://www.lon-capa.org/ |
# http://www.lon-capa.org/ |
|
|
use strict; |
use strict; |
use Sys::Hostname::FQDN(); |
|
use Term::ReadKey; |
|
use Locale::Country; |
|
use Crypt::OpenSSL::X509; |
|
use DateTime::Format::x509; |
|
use File::Slurp; |
|
use Cwd; |
|
|
|
# |
# |
# Expected structure |
# Expected structure |
Line 97 for use in the cluster.
|
Line 90 for use in the cluster.
|
|
|
END |
END |
|
|
#Proceed? |
print ('Continue? [Y/n]'); |
|
my $go_on = &get_user_selection(1); |
|
if (!$go_on) { |
|
exit; |
|
} |
|
|
|
require Sys::Hostname::FQDN; |
|
require Term::ReadKey; |
|
require Locale::Country; |
|
require Crypt::OpenSSL::X509; |
|
require DateTime::Format::x509; |
|
require File::Slurp; |
|
require Cwd; |
|
|
my ($dir,$hostname,%data); |
my ($dir,$hostname,%data); |
|
|
Line 152 END
|
Line 157 END
|
A configuration file: $dir/lonca/opensslca.conf will be created. |
A configuration file: $dir/lonca/opensslca.conf will be created. |
|
|
The following information will be included: |
The following information will be included: |
Country, State/Province, City, Cluster Name, Organizational Name, E-mail address, CA certificate lifetime (days), Default certificate lifetime (days), CRL re-creation interval (days) |
Country, State/Province, City, Cluster Name, Organizational Name, E-mail address, Default certificate lifetime (days), CRL re-creation interval (days) |
|
|
END |
END |
$hostname = Sys::Hostname::FQDN::fqdn(); |
$hostname = Sys::Hostname::FQDN::fqdn(); |
Line 171 END
|
Line 176 END
|
clustername => 'Cluster name', |
clustername => 'Cluster name', |
organization => 'Organization name', |
organization => 'Organization name', |
); |
); |
my ($clustername,$organization,$country,$state,$city,$email,$cadays,$clusterhostname,$days,$crldays); |
my ($clustername,$organization,$country,$state,$city,$email,$clusterhostname,$days,$crldays); |
$clusterhostname = $hostname; |
$clusterhostname = $hostname; |
$country = &get_country($hostname); |
$country = &get_country($hostname); |
print "Enter state or province name\n"; |
print "Enter state or province name\n"; |
Line 183 END
|
Line 188 END
|
'This name will be included as the Common Name for the CA certificate.'."\n"; |
'This name will be included as the Common Name for the CA certificate.'."\n"; |
$clustername = &get_info($fieldname{'clustername'}); |
$clustername = &get_info($fieldname{'clustername'}); |
print 'Enter the organization name for this LON-CAPA cluster, e.g., "Lon CAPA certification authority"'."\n". |
print 'Enter the organization name for this LON-CAPA cluster, e.g., "Lon CAPA certification authority"'."\n". |
'This name will be included as the Oraganization for the CA certificate.'."\n"; |
'This name will be included as the Organization for the CA certificate.'."\n"; |
$organization = &get_info($fieldname{'organization'}); |
$organization = &get_info($fieldname{'organization'}); |
print "Enter the lifetime (in days) for the CA root certificate distributed to all nodes, e.g., 3650\n"; |
|
$cadays = &get_days(); |
|
print "Enter the default lifetime (in days) for each certificate created/signed by the CA for individual nodes, e.g., 3650\n"; |
print "Enter the default lifetime (in days) for each certificate created/signed by the CA for individual nodes, e.g., 3650\n"; |
$days = &get_days(); |
$days = &get_days(); |
print "Enter the re-creation interval (in days) for the CA's certificate revocation list (CRL), e.g., 180\n"; |
print "Enter the re-creation interval (in days) for the CA's certificate revocation list (CRL), e.g., 180\n"; |
Line 224 organizationalUnitName = optional
|
Line 227 organizationalUnitName = optional
|
[ certificate_extensions ] |
[ certificate_extensions ] |
|
|
basicConstraints = CA:false |
basicConstraints = CA:false |
crlDistributionPoints = URI:http://$clusterhostname/adm/dns/loncapaCAcrl |
crlDistributionPoints = URI:http://$clusterhostname/adm/dns/loncapaCRL |
|
|
[ req ] |
[ req ] |
|
|
Line 313 END
|
Line 316 END
|
exit; |
exit; |
} |
} |
} |
} |
|
my $makecacert; |
if (-e "$dir/lonca/cacert.pem") { |
if (-e "$dir/lonca/cacert.pem") { |
print "A CA certificate exists\n"; |
print "A CA certificate exists\n"; |
open(PIPE,"openssl pkey -in $dir/lonca/private/cakey.pem -passin pass:$sslkeypass -pubout -outform der | sha256sum |"); |
open(PIPE,"openssl pkey -in $dir/lonca/private/cakey.pem -passin pass:$sslkeypass -pubout -outform der | sha256sum |"); |
Line 323 END
|
Line 327 END
|
my $hashfromcert = <PIPE>; |
my $hashfromcert = <PIPE>; |
close(PIPE); |
close(PIPE); |
chomp($hashfromcert); |
chomp($hashfromcert); |
|
my $defsel = 0; |
if ($hashfromkey eq $hashfromcert) { |
if ($hashfromkey eq $hashfromcert) { |
my ($now,$starttime,$endtime,$status,%cert); |
my ($now,$starttime,$endtime,$status,%cert); |
my $x509 = Crypt::OpenSSL::X509->new_from_file("$dir/lonca/cacert.pem"); |
my $x509 = Crypt::OpenSSL::X509->new_from_file("$dir/lonca/cacert.pem"); |
Line 351 END
|
Line 356 END
|
if ($endtime <= $now) { |
if ($endtime <= $now) { |
$status = 'previous'; |
$status = 'previous'; |
print "Current CA certificate expired $cert{'end'}\n"; |
print "Current CA certificate expired $cert{'end'}\n"; |
|
print 'Create a new certificate? [Y/n]'; |
|
$defsel = 1; |
} elsif ($starttime > $now) { |
} elsif ($starttime > $now) { |
$status = 'future'; |
$status = 'future'; |
print "Current CA certificate will be valid after $cert{'start'}\n"; |
print "Current CA certificate will be valid after $cert{'start'}\n"; |
|
print 'Create a new certificate? [y/N]'; |
} else { |
} else { |
$status eq 'active'; |
$status eq 'active'; |
print "Current CA certificate valid until $cert{'end'}".' '. |
print "Current CA certificate valid until $cert{'end'}".' '. |
"Signature Algorithm: $cert{'alg'}; Public Key size: $cert{'size'}\n"; |
"Signature Algorithm: $cert{'alg'}; Public Key size: $cert{'size'}\n"; |
} |
print 'Create a new certificate? [y/N]'; |
if ($status eq 'previous') { |
|
print 'Create a new certificate? [Y/n]'; |
|
if (&get_user_selection(1)) { |
|
unless (&make_ca_cert("$dir/lonca/private","$dir/lonca",$sslkeypass)) { |
|
print "Failed to create CA cert\n"; |
|
exit; |
|
} |
|
} |
|
} |
} |
} else { |
} else { |
print "Could not determine validity of current CA certificate\n"; |
print "Could not determine validity of current CA certificate\n"; |
exit; |
print 'Create a new certificate? [Y/n]'; |
|
$defsel = 1; |
} |
} |
|
} else { |
|
print "Current CA certificate does not match key.\n"; |
|
print 'Create a new certificate? [Y/n]'; |
|
$defsel = 1; |
|
} |
|
if (&get_user_selection($defsel)) { |
|
$makecacert = 1; |
} |
} |
} else { |
} else { |
unless (&make_ca_cert("$dir/lonca/private","$dir/lonca",$sslkeypass)) { |
$makecacert = 1; |
|
} |
|
if ($makecacert) { |
|
print "Enter the lifetime (in days) for the CA root certificate distributed to all nodes, e.g., 3650\n"; |
|
my $cadays = &get_days(); |
|
unless (&make_ca_cert("$dir/lonca/private","$dir/lonca",$sslkeypass,$cadays)) { |
print "Failed to create CA cert\n"; |
print "Failed to create CA cert\n"; |
exit; |
exit; |
} |
} |
Line 614 sub get_password {
|
Line 627 sub get_password {
|
local $| = 1; |
local $| = 1; |
print $prompt.': '; |
print $prompt.': '; |
my $newpasswd = ''; |
my $newpasswd = ''; |
ReadMode 'raw'; |
Term::ReadKey::ReadMode('raw'); |
my $key; |
my $key; |
while(ord($key = ReadKey(0)) != 10) { |
while(ord($key = Term::ReadKey::ReadKey(0)) != 10) { |
if(ord($key) == 127 || ord($key) == 8) { |
if(ord($key) == 127 || ord($key) == 8) { |
chop($newpasswd); |
chop($newpasswd); |
print "\b \b"; |
print "\b \b"; |
Line 625 sub get_password {
|
Line 638 sub get_password {
|
print '*'; |
print '*'; |
} |
} |
} |
} |
ReadMode 'normal'; |
Term::ReadKey::ReadMode('normal'); |
print "\n"; |
print "\n"; |
return $newpasswd; |
return $newpasswd; |
} |
} |
Line 661 sub make_key {
|
Line 674 sub make_key {
|
# |
# |
|
|
sub make_ca_cert { |
sub make_ca_cert { |
my ($keydir,$certdir,$sslkeypass) = @_; |
my ($keydir,$certdir,$sslkeypass,$cadays) = @_; |
# generate SSL cert for CA |
# generate SSL cert for CA |
my $created; |
my $created; |
if ((-d $keydir) && (-d $certdir) && ($sslkeypass ne '')) { |
if ((-d $keydir) && (-d $certdir) && ($sslkeypass ne '') && ($cadays =~ /^\d+$/) && ($cadays > 0)) { |
my $cmd = "openssl req -x509 -key $keydir/cakey.pem -passin pass:$sslkeypass -new -batch -config $certdir/opensslca.conf -out $certdir/cacert.pem"; |
open(PIPE,"openssl req -x509 -key $keydir/cakey.pem -passin pass:$sslkeypass -new -days $cadays -batch -config $certdir/opensslca.conf -out $certdir/cacert.pem |"); |
print "Calling ||$cmd||\n"; |
|
open(PIPE,"openssl req -x509 -key $keydir/cakey.pem -passin pass:$sslkeypass -new -batch -config $certdir/opensslca.conf -out $certdir/cacert.pem |"); |
|
close(PIPE); |
close(PIPE); |
if (-f "$certdir/cacert.pem") { |
if (-f "$certdir/cacert.pem") { |
my $mode = 0600; |
my $mode = 0600; |
chmod $mode, "$certdir/cacert.pem"; |
chmod $mode, "$certdir/cacert.pem"; |
# chmod $mode, "$certdir/careq.pem"; |
|
# open(PIPE,"openssl ca -create_serial -out $certdir/cacert.pem -days 3650 -keyfile $keydir/cakey.pem -selfsign -config ./openssl.cnf -infiles $certdir/careq.pem |"); |
|
# close(PIPE); |
|
# if (-f "$certdir/cacert.pem") { |
|
# my $mode = 0600; |
|
# chmod $mode, "$certdir/cacert.pem"; |
|
# } |
|
$created= 1; |
$created= 1; |
} |
} |
} else { |
} else { |
print "Creation of CA root certificate failed. Missing one or more of: CA directory, CA key directory, or CA passphrase.\n"; |
print "Creation of CA root certificate failed. Missing one or more of: CA directory, CA key directory, CA passphrase, or certificate lifetime (number of days).\n"; |
} |
} |
return $created; |
return $created; |
} |
} |
Line 737 sub get_country {
|
Line 741 sub get_country {
|
($posscountry) = ($desiredhostname =~ /\.(a-z){2}$/); |
($posscountry) = ($desiredhostname =~ /\.(a-z){2}$/); |
} |
} |
if ($posscountry) { |
if ($posscountry) { |
my $countrydesc = &Locale::Country::code2country($posscountry); |
my $countrydesc = Locale::Country::code2country($posscountry); |
if ($countrydesc eq '') { |
if ($countrydesc eq '') { |
undef($posscountry); |
undef($posscountry); |
} |
} |
Line 754 sub get_country {
|
Line 758 sub get_country {
|
my $choice=<STDIN>; |
my $choice=<STDIN>; |
chomp($choice); |
chomp($choice); |
if ($choice ne '') { |
if ($choice ne '') { |
if (&Locale::Country::code2country(lc($choice))) { |
if (Locale::Country::code2country(lc($choice))) { |
$country=uc($choice); |
$country=uc($choice); |
$flag=1; |
$flag=1; |
} else { |
} else { |
Line 822 included in the CA certificate
|
Line 826 included in the CA certificate
|
4) State or Province: $data{'state'} |
4) State or Province: $data{'state'} |
5) City: $data{'city'} |
5) City: $data{'city'} |
6) E-mail: $data{'email'} |
6) E-mail: $data{'email'} |
7) CA certificate lifetime (days): $data{'cadays'} |
7) Default certificate lifetime for issued certs (days): $data{'days'} |
8) Default certificate lifetime for issued certs (days): $data{'days'} |
8) CRL recreation interval (days): $data{'crldays'} |
9) CRL recreation interval (days): $data{'crldays'} |
9) Everything is correct up above |
10) Everything is correct up above |
|
|
|
Enter a choice of 1-9 to change, otherwise enter 10: |
Enter a choice of 1-8 to change, otherwise enter 9: |
END |
END |
my $choice=<STDIN>; |
my $choice=<STDIN>; |
chomp($choice); |
chomp($choice); |
Line 875 END
|
Line 878 END
|
$data{'email'}=$choice2; |
$data{'email'}=$choice2; |
} elsif ($choice == 7) { |
} elsif ($choice == 7) { |
print(<<END); |
print(<<END); |
7) CA Root Certificate lifetime: $data{'cadays'} |
7) Default certificate lifetime: $data{'days'} |
Enter new value: |
|
END |
|
my $choice2=<>; |
|
chomp($choice2); |
|
$choice2 =~ s/\D//g; |
|
$data{'cadays'}=$choice2; |
|
} elsif ($choice == 8) { |
|
print(<<END); |
|
8) Default certificate lifetime: $data{'days'} |
|
Enter new value: |
Enter new value: |
END |
END |
my $choice2=<>; |
my $choice2=<>; |
chomp($choice2); |
chomp($choice2); |
$choice2 =~ s/\D//g; |
$choice2 =~ s/\D//g; |
$data{'days'}=$choice2; |
$data{'days'}=$choice2; |
} elsif ($choice == 9) { |
} elsif ($choice == 8) { |
print(<<END); |
print(<<END); |
9) CRL re-creation interval: $data{'crldays'} |
8) CRL re-creation interval: $data{'crldays'} |
Enter new value: |
Enter new value: |
END |
END |
my $choice2=<>; |
my $choice2=<>; |
chomp($choice2); |
chomp($choice2); |
$choice2 =~ s/\D//g; |
$choice2 =~ s/\D//g; |
$data{'crldays'}=$choice2; |
$data{'crldays'}=$choice2; |
} elsif ($choice == 10) { |
} elsif ($choice == 9) { |
$flag=1; |
$flag=1; |
foreach my $key (keys(%data)) { |
foreach my $key (keys(%data)) { |
$data{$key} =~ s{/}{ }g; |
$data{$key} =~ s{/}{ }g; |