## OpenCA - CA Command
## (c) 1998-2001 by Massimiliano Pala and OpenCA Group
##
##   File Name: bpCreateCSR
##     Version: $Revision: 1.7.2.2 $
##       Brief: create a request for new users
## Description: 
##  Parameters:

sub cmdBpCreateCSR {

	print startLogPage (gettext ("Create Request Batch Processor"));

	## datadirectory for the batchprocessor
	my $batch_dir  = getRequired ("BP_DIR");

	print addLogSection (gettext ("Running batch processor ..."));

	bpScanDir ($batch_dir, "bpCreateCSR");

	print addPreLogLine ("");
	print addLogLine (gettext ("Batch processor finished"));
	print closeLogSection ();

	print closePage();

}

sub bpCreateCSR {
	my $dir = $_[0];

	## check for ID
	if ( (-f $dir."/ID") and
	     (-f $dir."/acl/newCSR") and
	     (-f $dir."/public/hashedPIN") and
	     (-f $dir."/private/privateKey") and
	     (-f $dir."/private/purePIN") and
	     (-f $dir."/data/ROLE") and
	     (-f $dir."/data/DN") ) {

		## variables
		my $pin;
		my $hashedPIN;
		my $id;
		my $dn;
		my $role;
		my $key;

		## load the ID
		$id = $tools->getFile ($dir."/ID");
		if (not $id) {
			print addPreLogLine ("<FONT COLOR=#FF0000>".
				    i18nGettext (
                      "Cannot load the ID from the file __DIR__ - ID ignored.",
                      "__DIR__", "$dir/ID").
				    "</FONT>");
			return;
		}

		## load the PIN
		my $pin = $cryptoShell->getSMIME (
		                                  DECRYPT    => 1,
		                                  CERT       => getRequired ("BP_CERTIFICATE"),
		                                  KEY        => getRequired ("BP_KEY"),
		                                  USE_ENGINE => 1,
		                                  PASSWD     => $query->param ('passwd'),
		                                  INFILE     => $dir."/private/purePIN",
		                                  );
		( $pin ) = ( $pin =~ /-----BEGIN PIN-----[\n\r]*([^\n\r]*)[\n\r]*-----END PIN-----/i);
		if (not $pin) {
			print addPreLogLine (
			          "<FONT COLOR=#FF0000>".
			          i18nGettext (
				      "Cannot load the PIN because the decryption of the PIN failed - ID __ID__ ignored.",
			              "__ID__", $id).
			          "</FONT>");
			return;
		}

		## load the hashed PIN
		$hashedPIN = $tools->getFile ($dir."/public/hashedPIN");
		if (not $hashedPIN) {
			print addPreLogLine ("<FONT COLOR=#FF0000>".
				    i18nGettext (
                      "Cannot load the hashed PIN - ID __ID__ ignored.",
                      "__ID__", $id).
				    "</FONT>");
			return;
		}

		## load role
		$role = $tools->getFile ($dir."/data/ROLE");
		if (not $role) {
			print addPreLogLine ("<FONT COLOR=#FF0000>".
				    i18nGettext (
                      "Cannot load the ROLE to build the request - ID __ID__ ignored.",
                      "__ID__", $id).
				    "</FONT>");
			return;
		}

		## load the private key
		$key = $tools->getFile ($dir."/private/privateKey");
		if (not $key) {
			print addPreLogLine ("<FONT COLOR=#FF0000>".
				    i18nGettext (
                      "Cannot load the private key to build the new request - ID __ID__ ignored.",
                      "__ID__", $id).
				    "</FONT>");
			return;
		}

		## load DN
		$dn = $tools->getFile ($dir."/data/DN");
		if (not $dn) {
			print addPreLogLine ("<FONT COLOR=#FF0000>".
				    i18nGettext (
                      "Cannot load the DN to build the request - ID __ID__ ignored.",
                      "__ID__", $id).
				    "</FONT>");
			return;
		}

		## rebuild DN for automatic batchprocessor handling
		$dn =~ s/,\s*cn\s*=[^,]*,/,/i;
		$dn =~ s/^\s*cn\s*=[^,]*,//i;
		$dn = "CN=$id,$dn";

		## generate request
		my $csr = new OpenCA::REQ (
				SHELL   => $cryptoShell,
				KEYFILE => $dir."/private/privateKey",
				SUBJECT => $dn,
				PASSWD  => $pin,
				FORMAT  => "PEM");
		if (not $csr) {
			print addPreLogLine ("<FONT COLOR=#FF0000>".
				    i18nGettext (
                      "Cannot generate a new request - ID __ID__ ignored. <br>OpenCA::REQ fails with errorcode __ERRNO__.",
                      "__ID__", $id,
				      "__ERRNO__", $OpenCA::REQ::errno)."<br>".
				    $OpenCA::REQ::errval.
				    "</FONT>");
			return;
		}

		## compose request
		my $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)) {
			print addPreLogLine ("<FONT COLOR=#FF0000>".
				    i18nGettext (
                      "The database failed during counting the existing requests (error __ERRNO__). __ERRVAL__ - ID __ID__ ignored.",
				      "__ERRNO__", $db->errno(),
                      "__ERRVAL__", $db->errval(),
                      "__ID__", $id).
				    "</FONT>");
			return;
		} else {
			$req_elements++;
		}
		my $new_serial = ($req_elements << getRequired ("ModuleShift")) | getRequired ("ModuleID");
		$tmp .= "SERIAL = ".$new_serial."\n";
		$tmp .= "NOTBEFORE = " . $tools->getDate() . "\n";
		$tmp .= "PIN = ".$hashedPIN."\n";
		$tmp .= "RA = " . $query->param('ra') . "\n";
		$tmp .= "ROLE = $role\n";
		$tmp .= "SUBJECT = ".$dn."\n";
		$tmp .= "SUBJECT_ALT_NAME = ".$tools->getFile ($dir."/data/SUBJECT_ALT_NAME")."\n";
		$tmp .= "-----END HEADER-----\n";
		$tmp .= $csr->getPEM();
		$tmp .= $key;

		my $new_req;
		if( not $new_req = new OpenCA::REQ( SHELL=>$cryptoShell, DATA=>$tmp) ) {
			print addPreLogLine ("<FONT COLOR=#FF0000>".
				    i18nGettext (
                      "Cannot compose a new request - ID __ID__ ignored. <br>OpenCA::REQ fails with errorcode __ERRNO__.",
				      "__ERRNO__", $OpenCA::REQ::errno,
                      "__ERRVAL__", $OpenCA::REQ::errval,
                      "__ID__", $id).
				    "</FONT>");
			return;
        	}

		if( not $db->storeItem( 
					DATATYPE=>PENDING_REQUEST,
					OBJECT=>$new_req,
					INFORM=>PEM,
					MODE=>"INSERT" )) {
			print addPreLogLine ("<FONT COLOR=#FF0000>".
				    i18nGettext (
                      "The database failed during storing the new request (error __ERRNO__). __ERRVAL__ - ID __ID__ ignored.",
		 		      "__ERRNO__", $db->errno(),
                      "__ERRVAL__", $db->errval(),
                      "__ID__", $id).
		 		    "</FONT>");
			return;
		}

		##// store request's serial in newCSR
		$tools->saveFile (FILENAME => $dir."/public/csrList",
				DATA       => $new_req->getSerial()."\n".$tools->getFile ($dir."/public/csrList"));

		## get a hash from the key
        my $digest = $cryptoShell->getDigest (DATA      => $key,
                                              ALGORITHM => "sha1");

		##// save the key's digest in a file associated with the request
        my $filename = $dir."/keybackup/csr_".$new_req->getSerial().".keydigest";
        if (not $tools->saveFile (FILENAME => $filename, DATA => $digest)) {
			print addPreLogLine (
			 	    i18nGettext (
                      "Cannot write the digest of the private key to file __FILE__. Direct keyrecovery from certificate is not possible - continuing ...",
                      "__FILE__", $filename));
			return;
        }

		## remove permission to generate this new request
		if (not unlink $dir."/acl/newCSR") {
			print addPreLogLine ("<FONT COLOR=#FF0000>".
				    i18nGettext (
                      "Cannot remove permission to create a new request but the new request was already generated - ID __ID__.",
                      "__ID__", $id).
				    "</FONT>");
			return;
		}

		print addPreLogLine (i18nGettext ("Generated a new request for ID __ID__.", "__ID__", $id));

	}
}

1;
