Diff for /loncom/CrCA.pl between versions 1.2 and 1.3

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;

Removed from v.1.2  
changed lines
  Added in v.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>