#!/usr/bin/perl # The LearningOnline Network # CrGenerate - Generate a loncapa certificate request. # # $Id: CrGenerate.pl,v 1.4 2004/06/30 11:14:35 foxr Exp $ # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # LON-CAPA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt # # http://www.lon-capa.org/ # # # This script: # 1. Generates a private host key and certificate request/ # 2. Decodes the private host key # 3. Installs the private host key with appropriate permissions # in the appropriate directory (sorry to be vague about this, but # the installation directory is determined by external configuration # info). # 4. Constructs an email to the loncapa cluster administrator # consisting of a generic heading and the certificate request as a MIME # attachment. # 5. Sends the email and # 6. Cleans up after itself by removing any temp files generated. # # # Import section: use strict; use MIME::Entity; use Mail::Mailer; use LONCAPA::Configuration; use File::Copy; # Global variable declarations:4 my $SSLCommand; # Full path to openssl command. my $CertificateDirectory; # LONCAPA Certificate directory. my $KeyFilename; # Key filename (within CertificateDirectory). my $RequestEmail; # Email address of loncapa cert admin. my $WebUID; # UID of web user. my $WebGID; # GID of web user. my $Passphrase="loncapawhatever"; # Initial passphrase for keyfile my $RequestFile="loncapaRequest.pem"; # Name of Certificate request file. my $EncodedKey="hostkey.pem"; # Name of encoded key file. my $WebUser="www"; # Username running the web server. my $WebGroup="www"; # Group name running the web server. # Debug/log support: # my $DEBUG = 1; # 1 for on, 0 for off. # Send debugging to stderr. # Parameters: # msg - Message to send to stderr. # Implicit Inputs: # $DEBUG - message is only written if this is true. # sub Debug { my $msg = shift; if($DEBUG) { print STDERR "$msg\n"; } } # # Read the LonCAPA web config files to get the values of the # configuration global variables we need: # Implicit inputs: # loncapa.conf - configuration file to read (user specific). # Implicit outputs (see global variables section): # SSLCommand, # CertificateDirectory # KeyfileName # RequestEmail # Side-Effects: # Exit with error if cannot complete. # sub ReadConfig { Debug("Reading configuration"); my $perlvarref = LONCAPA::Configuration::read_conf('loncapa.conf'); # Name of the SSL Program if($perlvarref->{SSLProgram}) { $SSLCommand = $perlvarref->{SSLProgram}; Debug("SSL Command: $SSLCommand"); } else { die "Unable to read the SSLCommand configuration option\n"; } # Where the certificates, and host key are installed: if($perlvarref->{lonCertificateDirectory}) { $CertificateDirectory = $perlvarref->{lonCertificateDirectory}; Debug("Local certificate Directory: $CertificateDirectory"); } else { die "Unable to read SSLDirectory configuration option\n"; } # The name of the host key file (to be installed in SSLDirectory). # if($perlvarref->{lonnetPrivateKey}) { $KeyFilename = $perlvarref->{lonnetPrivateKey}; Debug("Private key will be installed as $KeyFilename"); } else { die "Unable to read lonnetPrivateKey conrig paraemter\n"; } # The email address to which the certificate request is sent: if($perlvarref->{SSLEmail}) { $RequestEmail = $perlvarref->{SSLEmail}; Debug("Certificate request will be sent to $RequestEmail"); } else { die "Could not read SSLEmail coniguration key"; } # The UID/GID of the web user: It's possible the web user's # GID is not its primary, so we'll translate that form the # group file separately. my ($login, $pass, $uid, $gid) = getpwnam($WebUser); if($uid) { $WebUID = $uid; Debug("Web user: $WebUser -> UID: $WebUID"); } else { die "Could not translate web user: $WebUser to a uid."; } my $gid = getgrnam($WebGroup); if($gid) { $WebGID = $gid; Debug("Web group: $WebGroup -> GID $WebGID"); } else { die "Unable to translate web group $WebGroup to a gid."; } } # # Generate a certificate request. # The openssl command is issued to create a local host key and # a certificate request. The key is initially encoded. # We will eventually decode this, however, since the key # passphrase is open source we'll protect even the initial # encoded key file too. We'll need to decode the keyfile since # otherwise, openssl will need a passphrase everytime an ssl connection # is created (ouch). # Implicit Inputs: # Passphrase - Initial passphrase for the encoded key. # RequestFile - Filename of the certificate request. # EncodedKey - Filename of the encoded key file. # # Side-Effects: # sub GenerateRequest { Debug("Generating the request and key"); print "We are now going to generate the certificate request\n"; print "You will be prompted by openssl for several pieces of \n"; print "information. Most of this information is for documentation\n"; print "purposes only, so it's not critical if you make a mistake.\n"; print "However: The generated certificate will be sent to the \n"; print "Email address you provide, and you should leave the optional\n"; print "Challenge password blank.\n"; my $requestcmd = $SSLCommand." req -newkey rsa:1024 " ." -keyout hostkey.pem " ." -keyform PEM " ." -out request.pem " ." -outform PEM " ." -passout pass:$Passphrase"; my $status = system($requestcmd); if($status) { die "Certificate request generation failed: $status"; } chmod(0600, "hostkey.pem"); # Protect key since passphrase is opensrc. Debug("Decoding the key"); my $decodecmd = $SSLCommand." rsa -in hostkey.pem" ." -out hostkey.dec" ." -passin pass:$Passphrase"; my $status = system($decodecmd); if($status) { die "Host key decode failed"; } chmod(0600, "hostkey.dec"); # Protect the decoded hostkey. Debug("Done"); } # # Installs the decoded host key (hostkey.dec) in the # certificate directory with the correct permissions. # # Implicit Inputs: # hostkey.dec - the name of the host key file. # $CertificateDirectory - where the key file gets installed # $KeyFilename - Final name of the key file. # $WebUser - User who should own the key file. # $WebGroup - Group who should own the key file. # 0400 - Permissions to give to the installed key # file. # 0700 - Permissions given to the certificate # directory if created. # Side-Effects: # If necessary, $CertificateDirectory is created. # $CertificateDirectory/$KeyFilename is ovewritten with the # contents of hostkey.dec in the cwd. # sub InstallKey { Debug("InstallKey"); Debug("Need to create certificate directory?"); if(!(-d $CertificateDirectory)) { Debug("Creating"); mkdir($CertificateDirectory, 0700); chown($WebUID, $WebGID, $CertificateDirectory); } else { Debug("Exists"); } Debug("Installing the key file:"); my $FullKeyPath = $CertificateDirectory."/".$KeyFilename; copy("hostkey.dec", $FullKeyPath); Debug("Setting ownership and permissions"); chmod(0400, $FullKeyPath); chown($WebUID, $WebGID, $FullKeyPath); Debug("Done"); } sub MailRequest {} sub Cleanup {} # Entry point: Debug("Starting program"); ReadConfig; # Read loncapa apache config file. GenerateRequest; # Generate certificate request. InstallKey; # Install the user's key. MailRequest; # Mail certificate request to loncapa Cleanup; # Cleanup temp files created. Debug("Done");