## OpenCA - Public Web-Gateway Command
## (c) 1998-2001 by Massimiliano Pala and OpenCA Group
##
##   File Name: pkcs10_req
##       Brief: pkcs10 request handling
## Description: pkcs10 requests will be handled by this script
##  Parameters: 
 
require "$common_libs/csr-utils.lib";
 
sub cmdPkcs10_req {

my $PRG = gettext("pkcs#10 Requests Manager");
my $VER = "0.1.5";

## Set the needed Parameters
my $shell           = getRequired('openssl');

my $formFile        = getRequired('PKCS10_ReqStartForm');
our $formFile2       = getRequired('PKCS10_ReqConfirmForm');

my $successPage     = getRequired('PKCS10_ReqSuccessPage');

my $minPinLength    = getRequired('minpinlength');

our ( $dn, $modulus, $alg, $reqObj, $notBefore );

our @myParams       = ();
our @myParamsValues = ();
my $tmpPar;

## Set the new variables for the Input elements and Checking values
## my @myparnames = ( 'operation','upload',   'passwd1','passwd2',
## 		   'sessionid','ra',     'request');

## Define the parameters values and general expressions
push (@myParams, {(-regx=>'*',
	    -intype=>'hidden',
	    -name=>'operation',
	    -value=>'server-filled-form')} );
push (@myParams, {(-regx=>'TEXT',
	    -intype=>'filefield',
	    -default=>'req.pem',
	    -size=>20,
	    -name=>'upload')} );
push (@myParams, {(-regx=>'*',
	    -intype=>'password_field',
	    -name=>'passwd1',
	    -size=>16,
	    -minlen=>$minPinLength)} );
push (@myParams, {(   -regx=>'*',
	    -intype=>'password_field',
	    -name=>'passwd2',
	    -size=>16,
	    -minlen=>$minPinLength)} );
push (@myParams, {(  -regx=>'*',
	    -intype=>'textfield',
	    -name=>'sessionid')} );
push (@myParams, {(   -regx=>'*',
	    -intype=>'popup_menu',
	    -name=>'ra',
	    -values=>($config->getParam('RegistrationAuthority'))->{VALUES})} );

push (@myParams, {(     -regx=>'LETTERS',
                        -intype=>'popup_menu',
                        -name=>'role',
                        -values=>[loadRoles()])});

## Generate the Parameters (Input Objects) : the names must match
## ones included in the form;
foreach $tmpPar ( @myParams ) {
        push (@myParamsValues, {NAME=>$tmpPar->{-name},
                                VALUE=> $query->newInput($tmpPar)} );
}

## Check parameters, make reqs for Certificates and so on, depending on the
## CGI status contained in the $OPERATION variable ( below )

if( $query->param('operation') eq "") {
    printFormOne( FILENAME=>$formFile );
    return 1;   
} 

## Check Environment Settings
my $HTTP_REFERER = $query -> referer();

## Check FORM : try to identify if the form has already been
## completed and needs confirmation or if we are in the earlier
## status ( checking for the correct parameters )

my $OPERATION   = $query->param('operation');

our $PASSWD	= $query->param('passwd1');
our $PASSWD2	= $query->param('passwd2');
my $UPLOAD	= $query->param('upload');

## Get Registration Authority
my $RA          = $query->param('ra');
my $ROLE        = $query->param ('role');

## Filled FORM for user certification;
## distinguished operation from form Status.

checkPkcs10_req() if ($OPERATION);

if ($OPERATION eq 'server-filled-form') {
	my $tmp, $i;

	my $filename 	= $query->param('upload');
	my $fh 		= $query->upload('upload');
	my $type 	= $query->uploadInfo($filename)->{'Content-Type'};

	if ((!($fh)) && ($query->cgi_error)) {
		generalError(gettext ("ERROR: request retrival failed!"));
   	} else {
		while( $tmp = <$fh>) {
			$request .= $tmp;
		}
	}

	## fix PKCS#10 requests of critical path
	$request =~ s/-----BEGIN PKCS#10 CERTIFICATE REQUEST-----/-----BEGIN CERTIFICATE REQUEST-----/;
	$request =~ s/-----END PKCS#10 CERTIFICATE REQUEST-----/-----END CERTIFICATE REQUEST-----/;

	$reqObj = new OpenCA::REQ( SHELL=>$cryptoShell, DATA=>$request );
	if( not $reqObj ) {
		generalError(gettext ("ERROR: not a PKCS#10 PEM request received!"));
	}

	$alg       = $reqObj->getParsed()->{PK_ALGORITHM};
	$modulus   = $reqObj->getParsed()->{KEYSIZE};
	$subject   = $reqObj->getParsed()->{DN};

	$tmp = `date`; chop( $tmp );
	$notBefore = ( "$tmp" or gettext("n/a") );
	$subject =~ s/\,\ /,/g;
	$subject =~ s/\//,/g;

	my @ls = reverse split( /\,/, $subject );

	foreach $i (@ls) {
		$dn .= $i . "<BR>\n" if( $i !~ /\,/ );
	}

	$query->param(-name=>'request', -value=>$request );
	clientFilledForm();
};

if ($OPERATION eq 'server-confirmed-form') {

	my ( $tmp, $req );

	$tmp = "-----BEGIN HEADER-----\n";
	$tmp .= "TYPE = PKCS#10\n";
	my $last_req = libDBGetLastItem ("REQUEST");
	my $req_elements = 0;
	$req_elements    = $last_req->getSerial("REQUEST") if ($last_req);
	$req_elements  >>= getRequired ("ModuleShift");
        if ((not defined $req_elements) or ($req_elements < 0)) {
		generalError (gettext ("The database fails during counting the already existing requests!"));
        } else {
        	$req_elements++;
        }
        my $new_serial = ($req_elements << getRequired ("ModuleShift")) | getRequired ("ModuleID");
        $tmp .= "SERIAL = $new_serial\n";
	$tmp .= "NOTBEFORE = " . $tools->getDate() . "\n";
        my $PASSWD = $query->param('passwd1');
        if ($PASSWD) {
		my $pin_digest = $cryptoShell->getDigest (
                             DATA      => $PASSWD,
                             ALGORITHM => "sha1");
		if (not $pin_digest) {
			generalError (gettext ("OpenSSL fails during calculating the hash of the passphrase!"));
		}
		$tmp .= "PIN = $pin_digest\n";
        }
	$tmp .= "RA = " . $query->param('ra') . "\n";
	$tmp .= "ROLE = $ROLE\n";
	$tmp .= "-----END HEADER-----\n";
	$tmp .= $query->param('request');

	if( not $req = new OpenCA::REQ( SHELL=>$cryptoShell, DATA=>$tmp) ) {
		generalError( gettext ("Internal Request Error"), 978 );
	}

	if( not $db->storeItem( DATATYPE=>PENDING_REQUEST,
				OBJECT=>$req, INFORM=>PEM, MODE=>"INSERT" )) {
		generalError( gettext ("Error while storing REQ in database!") );
	};
  
	my $ret;

	if( not $ret = $tools->getFile( $successPage )) {
		configError (i18nGettext ("Cannot load file __FILE__!", "__FILE__", $successPage) ) if ( not $ret );
	}

	$ret = $query->subVar($ret,"\@CSR_SERIAL\@",$req->getSerial());

	print "$ret";

	return 1;

} 

} ## end cmdPkcs10_req

sub checkPkcs10_req {

    my $state = $_[0];

    ## Checking for Boguous Systems ( POST method, REFERER doc, etc... )
    my $METHOD       = $query->request_method();
    if ($METHOD !~ /POST/i) {
        generalError (gettext ("This command is only usable with forms which are using POST as METHOD!"));
    };

    return 1;
}
1;
