--- loncom/CrCA.pl 2019/07/08 23:00:16 1.3 +++ loncom/CrCA.pl 2019/07/18 00:28:04 1.4 @@ -2,7 +2,7 @@ # The LearningOnline Network with CAPA # Script to create a Certificate Authority (CA) for a LON-CAPA cluster. # -# $Id: CrCA.pl,v 1.3 2019/07/08 23:00:16 raeburn Exp $ +# $Id: CrCA.pl,v 1.4 2019/07/18 00:28:04 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -72,6 +72,8 @@ Term::ReadKey Sys::Hostname::FQDN Locale::Country Crypt::OpenSSL::X509 +Crypt::X509::CRL +MIME::Base64 DateTime::Format::x509 File::Slurp @@ -96,13 +98,51 @@ END exit; } - require Sys::Hostname::FQDN; - require Term::ReadKey; - require Locale::Country; - require Crypt::OpenSSL::X509; - require DateTime::Format::x509; - require File::Slurp; - require Cwd; + eval { require Sys::Hostname::FQDN; }; + if ($@) { + print "Could not find required perl module: Sys::Hostname::FQDN. Exiting.\n"; + exit; + } + eval { require Term::ReadKey; }; + if ($@) { + print "Could not find required perl module: Term::ReadKey. Exiting\n"; + exit; + } + eval { require Locale::Country; }; + if ($@) { + print "Could not find required perl module: Locale::Country. Exiting\n"; + exit; + } + eval { require Crypt::OpenSSL::X509; }; + if ($@) { + print "Could not find required perl module: Crypt::OpenSSL::X509. Exiting\n"; + exit; + } + eval { require Crypt::X509::CRL; }; + if ($@) { + print "Could not find required perl module: Crypt::X509::CRL. Exiting\n"; + exit; + } + eval { require DateTime::Format::x509; }; + if ($@) { + print "Could not find required perl module: DateTime::Format::x509. Exiting\n"; + exit; + } + eval { require File::Slurp; }; + if ($@) { + print "Could not find required perl module: File::Slurp. Exiting\n"; + exit; + } + eval { require MIME::Base64; }; + if ($@) { + print "Could not find required perl core module: MIME::Base64\n"; + exit; + } + eval { require Cwd; }; + if ($@) { + print "Could not find required perl core module: Cwd\n"; + exit; + } my ($dir,$hostname,%data); @@ -388,7 +428,7 @@ END 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 certificate\n"; exit; } } @@ -403,25 +443,98 @@ END print "lonca/index.txt file is missing\n"; exit; } -# echo 1000 > serial - - unless (-e "$dir/lonca/crl/loncapaCAcrl.pem") { - open(PIPE,"openssl ca -gencrl -keyfile $dir/lonca/private/cakey.pem -cert $dir/lonca/cacert.pem -out $dir". - "/lonca/crl/loncapaCAcrl.pem -config $dir/lonca/opensslca.conf -passin pass:$sslkeypass |"); - close(PIPE); - if (-e "$dir/lonca/crl/loncapaCAcrl.pem") { - print "Certificate Revocation List created\n"; + my $defcrlsel = 1; + if (!-e "$dir/lonca/crl/loncapaCAcrl.pem") { + print "No Revocation Certificate List found.\n"; + print 'Create Certificate Revocation List [Y/n]'; + } else { + if (open(PIPE,"openssl crl -in $dir/lonca/crl/loncapaCAcrl.pem -inform pem -CAfile $dir/lonca/cacert.pem -noout 2>&1 |")) { + my $crlstatus = ; + close(PIPE); + chomp($crlstatus); + my $failmsg = "Could not determine 'valid from' and 'valid to' dates for Certificate Revocation List.\n"; + if ($crlstatus =~ /OK/) { + print "Current Certficate Revocation List is consistent with current CA certificate.\n"; + if (open(my $fh,'<',"$dir/lonca/crl/loncapaCAcrl.pem")) { + my $pem_crl = ''; + while (my $line=<$fh>) { + chomp($line); + next if ($line eq '-----BEGIN X509 CRL-----'); + next if ($line eq '-----END X509 CRL-----'); + $pem_crl .= $line; + } + close($fh); + my $der_crl = MIME::Base64::decode_base64($pem_crl); + if ($der_crl ne '') { + my $decoded = Crypt::X509::CRL->new( crl => $der_crl ); + if (ref($decoded)) { + if ($decoded->error) { + print $failmsg; + } else { + my $starttime = $decoded->this_update; + my $endtime = $decoded->next_update; + if (($endtime ne '') && ($endtime < time)) { + print "Certificate Revocation List is no longer valid.\n"; + } elsif ($starttime > time) { + print "Certificate Revocation List will become valid in the future.\n"; + } elsif (($starttime ne '') && ($endtime ne '')) { + my $showstart = localtime($starttime); + my $showend = localtime($endtime); + print "Certificate Revocation List valid from: $showstart to: $showend\n"; + $defcrlsel = 0; + } else { + print $failmsg; + } + } + } else { + print $failmsg; + } + } else { + print $failmsg; + } + } else { + print $failmsg; + } + } else { + print "Current Certificate Revocation List is not consistent with current CA certificate.\n"; + } + if ($defcrlsel) { + print 'Create Certificate Revocation List [Y/n]'; + } else { + print 'Create Certificate Revocation List [y/N]'; + } + } else { + print "Could not check Certificate Revocation List status.\n"; + print 'Create Certificate Revocation List [Y/n]'; } } - if (-e "$dir/lonca/crl/loncapaCAcrl.pem") { - open(PIPE,"openssl crl -in $dir/lonca/crl/loncapaCAcrl.pem -inform pem -CAfile $dir/lonca/cacert.pem -noout 2>&1 |"); - my $revoked = ; - close(PIPE); - chomp($revoked); - print "Revocation certificate status: $revoked\n"; -# Create a new one? + if (&get_user_selection($defcrlsel)) { + if (open(PIPE,"openssl ca -gencrl -keyfile $dir/lonca/private/cakey.pem -cert $dir/lonca/cacert.pem -out $dir". + "/lonca/crl/loncapaCAcrl.pem -config $dir/lonca/opensslca.conf -passin pass:$sslkeypass |")) { + close(PIPE); + if (-e "$dir/lonca/crl/loncapaCAcrl.pem") { + if (open(PIPE,"openssl crl -in $dir/lonca/crl/loncapaCAcrl.pem -inform pem -CAfile $dir/lonca/cacert.pem -noout 2>&1 |")) { + my $revoked = ; + close(PIPE); + chomp($revoked); + if ($revoked eq 'verify OK') { + print "Certificate Revocation List created\n"; + } else { + print "Certificate Revocation List status: $revoked\n"; + } + } else { + print "Could not check Certificate Revocation List status\n"; + } + } else { + print "Failed to create Certificate Revocation List\n"; + } + } else { + print "Failed to create Certificate Revocation List\n"; + } } + exit(0); + sub cafield_to_key { my %mapping = ( @@ -818,7 +931,8 @@ sub confirm_config { print(<; chomp($choice);