#!/usr/bin/perl # renewUserCert.pl - automatically get a new certificate issued based on the # valid X.509 certificate that is used to authenticate the connection. # # Generates a certficate request based on a current X.509 certificate and # submits it to an iPlanet CA server. The current key is used for the # new certificate unless the -newkey option is specified. # any parameters (except debug, help and dir) that are omitted # will be promted for. # # Sample Usage: # renewUserCert - will renew your usercert.pem in your .globus directory # it will prompt for the passphrase that was used to # encypt userkey.pem # -email - the user's email address # -phone - the user's 10 digit phone number # -passin pass - file containing password for the currrent private key # if omitted, openssl will prompt for a passphrase # -passout pass - file containing password for the new private key # if omitted, openssl will prompt for a passphrase # only used if the -newkey switch is given. # -cert - Certificate that is to be replaced # Defaults to usercert.pem # -key - private key corresponsding to the certificate # Defaults to userkey.pem # -dir - the directory in which to find the key and cert to be # replaced and to store the new one. # defaults to $HOME/.globus # -prefix - Causes the certificate to be renewed to be # cert.pem and key.pem # instead of usercert.pem and userkey.pem # -newkey - if given a new key will be generated. # if omitted the current key will be used for the new cert # -debug - sets the debug flag, causing lots of debugging info # to be spewed to the console # -help - will print a usage message # modified version - Dhiva sep 16, 2004 dhiva@es.net # Modified the requestCert script to talk to the replace # cert interface. # change History : HIDDEN parameters - more parameters have been included # removed $OPTFIELDS, $SUBJECT, $USERID # no need to ask for the Full Name ot generate random number # because this interface preserves the # subjectDN from the current certificate # # version 1.0 - Oct, 2004 mrthompson@lbl.gov # based on Dhiva's UserGridEnrollment and Steve Chan's makecert.pl scripts # use Getopt::Long; # url for the CA server's user certificate request interface #use the following two lines for the fusionGrid CA #my $baseURL = "https://jade.es.net:9002/enrollment"; # fusion CA #my $dc2 = "FusionGrid"; #use the following two lines for the DOEGrids CA my $baseURL = "https://pki1.doegrids.org/enrollment"; # doegrids CA my $dc2 = "doegrids"; # files used for openssl certificate request my $credDir = $ENV{HOME}."/.globus"; my $usercert = "usercert.pem"; my $userkey = "userkey.pem"; my $newkey = "newuserkey.pem"; my $newcert = "newusercert.pem"; my $reqfile = "/tmp/".$$."req.pem"; my $tempCertKey = "/tmp/certkey.$$"; my $passinarg =""; my $passoutarg =""; my $password =""; my $prefix=""; my $randfile = "/tmp/random.$$"; my $sslconf = "/tmp/sslconf.$$"; my $verbose = "-s"; my $insecure ="-k"; my $gennewkey = 0; # file for output from the certificate request my $output_file = "/tmp/response.$$.html"; my $curlVersion = `curl --version | awk \'{ print \$2 }\'`; ########################################################### # SUBSCRIBER PERSONAL INFORMATION ########################################################### my $csrRequestorName="NOTUSED"; my $csrRequestorEmail=""; my $csrRequestorPhone=""; my $csrRequestorAffiliation="FusionGrid"; #############OPTIONAL-FIELDS############################### ########################################################### my $COMMENT="csrRequestorComments=None"; my $PWDFLDS="challengePassword=''&confirmChallengePassword=''"; $PWDFLDS =~ s/ //g; $COMMENT =~ s/ /+/g; $OPTFIELDS="-d \"$COMMENT&$PWDFLDS\""; ########################################################### # Hidden form fields - These are all defaults # Standard Parameters required by the Service # ********** DO NOT CHANGE THESE VALUES ****************** ########################################################### my $HIDDEN = "requestFormat=clientAuth& certType=client& certauthEnrollType=single& certauthEnroll=on& ssl_client=true& ssl_server=true& digital_signature=true& non_repudiation=true& key_encipherment=true& data_encipherment=true& AuthServerRequest=false& doSslAuth=on& authenticator=UidPwdDirAuth& uid=doegridsuser& pwd=doegridsuser& email=true"; ########################################################### # replace the spaces with + symbol ########################################################### $HIDDEN =~ s/\s//g; $HIDDEN = "-d \"$HIDDEN\""; # hash for the command line args initialized to null strings my @keys = qw(email phone cert key passin passout dir prefix ); my %args; @args{@keys} = ("") x @keys; GetOptions( \%args,"email=s","phone=s","cert=s","key=s","passin=s","passout=s","dir=s", "prefix=s", "newkey+","debug+","help+"); if ( $args{help}) { usage(); exit 1; } if ($args{debug}) { $verbose = "-v"; } if ($args{newkey}) { $gennewkey = 1; } if ( $args{prefix} ) { $usercert = $args{prefix} . "cert.pem"; $userkey = $args{prefix} . "key.pem"; $newcert = $args{prefix} . "newcert.pem"; $newkey = $args{prefix} . "newkey.pem"; } if ($args{key}) { $userkey = $args{key}; $newkey = "new" . $userkey; } if ($args{cert} ) { $usercert = $args{cert}; $newcert = "new" . $usercert } if ($args{dir}) { $credDir = $args{dir}; if ( ! -d $credDir) { printf "$credDir does not exist\n"; exit 1; } } $newkey = $credDir."/". $newkey; $newcert = $credDir."/" . $newcert; $usercert = $credDir . "/" . $usercert; $userkey = $credDir . "/" . $userkey; if (! -r $usercert) { print "$usercert does not exist\n"; exit 1; } if ( ! -r $userkey) { print "$userkey does not exist\n"; exit 1; } if ( $args{passin}){ $passinarg = "-passin file:$args{passin}"; } else { print "Enter passphrase for $userkey: "; system "stty -echo"; chomp( $password = ); print "\n"; system "stty echo"; $passinarg = "-passin pass:$password"; } if ($args{passout}) { $passoutarg = "passout file:$args{passout}"; } else { if ($gennewkey){ print "you will be prompted for a passphrase to encyrpt the private key that is being generated.\n"; } } #combine cert and key into one file for use by curl for https client-side auth `cat $usercert $userkey > $tempCertKey`; `chmod 600 $tempCertKey`; # curl started requiring the server CA cert in verion 7.10, the -k switch overides the check @vers = split /\./, $curlVersion; if ($vers[0] <= 7) { if ($vers[1] <= 9 ) { $insecure = ""; } } # setup config file for the openssl stuff umask 0x600; open SSLCONF, ">$sslconf" || die "Could not setup openssl config file $sslconf"; print SSLCONF < $randfile`; `head -n1000 /dev/urandom >> $randfile` if ( -e "/dev/urandom" ); `ps -aux >> $randfile`; `ls -ln /tmp >> $randfile`; # Generate certificate request my $cmd; if ($gennewkey) { ($cmd) = sprintf("openssl req -new $passoutarg -out %s -config %s",$reqfile,$sslconf); } else { ($cmd) = sprintf( "openssl req -new $passinarg -key %s -out %s -config %s",$userkey,$reqfile, $sslconf); } if ($args{debug}) { print $cmd."\n"; } $res = system( $cmd ); if ($res) { die "Error while executing $cmd"; } if ($gennewkey){ `chmod 600 $newkey`; } unlink $sslconf; # Get the rest of the input arguments while (! grep /@/, $args{email} ) { print "input your email address: "; $args{email} = ; $args{email} =~ s/^\s*(.*?)\s*$/$1/; } $csrRequestorEmail = $args{email}; while ( length( $args{phone}) < 10 ) { print "input your 10 digit phone number: "; $args{phone} = ; $args{phone} =~ s/^\s*(.*?)\s*$/$1/; } $csrRequestorPhone = $args{phone}; ; my $FORMFIELDS="csrRequestorName=$csrRequestorName& csrRequestorEmail=$csrRequestorEmail& csrRequestorPhone=$csrRequestorPhone& csrRequestorAffiliation=$csrRequestorAffiliation& SponsorEmail= & SponsorPhone= & SponsorName= "; $FORMFIELDS =~ s/\&\s/\&/g; $FORMFIELDS =~ s/\s/+/g; $FORMFIELDS = "-d \"$FORMFIELDS\""; # Build a command line for curl # XXX Solaris grep does not take -A switch $CR=`grep -A100 BEG $reqfile | grep -B100 END`; $CR =~ s/\n/%0d%0a/g; $CR =~ s/\+/%2B/g; $CR =~ s/\//%2F/g; $CR =~ s/=/%3D/g; $CR =~ s/ /+/g; $CR = "-d pkcs10Request=$CR"; # the -k (insecure) switch turns off curl's check for a trusted CA on the server # certificate when using https. curl looks in .../share/curl/cur-ca-bundle.crt # by default. # you can give it a different ca bundle by using the -cacert option. # if it can't find a bundle at all, it will skip the check. $passinarg =""; if ($password ne ""){ $passinarg = "--pass $password"; } elsif ( $args{passin}){ if (open PD, $args{passin}) { chomp( $password = ); $passinarg = "--pass $password"; close PD; } else { print "unable to open $args{passin}. Curl will prompt for password\n"; } } else { print "Connecting to the CA. You will be prompted for the passphrase for $userkey.\n"; } $curlcmd = "curl $verbose $insecure -S --random-file $randfile --cert $tempCertKey $passinarg $HIDDEN $CR $FORMFIELDS $baseURL > $output_file"; if ($args{debug}) { print $curlcmd."\n"; } $res = system($curlcmd); unlink $tempCertKey, $randfile; if ($res) { die "Error executing $curlcmd"; } open OF, $output_file or die "can't open $output_file $!\n"; @output = ; if ($args{debug}) { print @output; } unlink $reqfile, $output_file; ########################################################### # Copy out the certificate if the call was successful # otherwise print the error message ########################################################### @CMS_error = grep /^fixed\.unexpectedError/, @output; if ( @CMS_error == 1) { print "Unable to retrieve certificate. Please check the certificate number.\n"; $CMS_error[0] =~ s/^fixed\.unexpectedError = //; print $CMS_error[0] . "\n"; exit 1; } @CMS_Policy_Error_Info = grep /^record\.policyMessage/, @output; if ( @CMS_Policy_Error_Info == 1){ $CMS_Policy_Error = $CMS_Policy_Error_Info[0]; $CMS_Policy_Error =~ s/record.policyMessage.*?=//; $CMS_Policy_Error =~ s/<.*?>//g; # get rid of html tags $CMS_Policy_Error =~ s/;//g ; print "$CMS_Policy_Error\n"; exit 1; } @retCert = grep /^record\.base64Cert/, @output; if ( @retCert == 0 ) { print "Request to CA failed.\nDumping reply html page\n\n"; if (! $args{debug}) { print @output; } exit 1; } $retCert[0] =~ s/.*\"(.+)\".*/$1/; $retCert[0] =~ s/\\n/\n/g; open CERTFILE, ">$newcert" || die "Could not write to $newcert\n"; print CERTFILE $retCert[0] . "\n"; close CERTFILE; print "your renewed certificate is in $newcert You can move it to $usercert to replace your current one\n"; if ($gennewkey){ print "Your new key is in $newkey and should be moved to $userkey\n"; } print "\nPlease ignore the mail that you will receive from the CA. It only applies to certificate requests that were made via a web browser\n"; ################### Usage ############################### sub usage { print "usage is : -cert defaults to usercert.pem -key defaults to userkey.pem -passin -passout only used if the -newkey switch is given -email required -phone required -prefix Causes the certificate to be renewed to be cert.pem and key.pem instead of usercert.pem and userkey.pem -dir defaults to $ENV{HOME}/.globus -newkey generate a new key for the new certificate -debug spews lots of output to the terminal -help prints this message any omitted and required arguments will be prompted for\n"; }